TranslateAnimation动画失效问题:自定义多阶段路径动画无法正常执行
修复TranslateAnimation动画不工作的问题
我来帮你分析下当前代码的问题,以及如何实现你想要的「从屏幕左下角→右侧中间→屏幕中心」的动画效果:
问题诊断
你的代码里有几个关键错误导致动画不符合预期:
- 起始坐标错误:你设置的
fromXDelta是screenWidthPx(屏幕最右侧),但需求是从屏幕左下角出发,左下角的X坐标应该是0,Y坐标是screenHeightPx(屏幕底部)。 - 坐标模式默认是相对自身:
TranslateAnimation无类型参数的构造方法,默认使用RELATIVE_TO_SELF作为坐标参考,也就是说你设置的数值是相对于View自身位置的偏移,而不是绝对屏幕坐标。这会导致动画完全偏离预期路径。 - 动画路径不符合需求:当前代码只让View在水平方向从右侧移动到中间,垂直方向完全没变化,既没从左下角开始,也没到屏幕中心。
解决方案
方法1:修正TranslateAnimation(补间动画)
如果你坚持用TranslateAnimation,需要使用带坐标类型参数的构造方法,指定ABSOLUTE(绝对屏幕坐标),并分两步实现完整路径:
Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int screenWidthPx = size.x; int screenHeightPx = size.y; // 第一步:从屏幕左下角移动到右侧中间 TranslateAnimation firstSlide = new TranslateAnimation( Animation.ABSOLUTE, 0f, // 起始X:绝对坐标0(屏幕最左) Animation.ABSOLUTE, screenWidthPx, // 目标X:绝对坐标屏幕宽度(屏幕最右) Animation.ABSOLUTE, screenHeightPx, // 起始Y:绝对坐标屏幕高度(屏幕最下) Animation.ABSOLUTE, screenHeightPx / 2f // 目标Y:绝对坐标屏幕高度的一半(垂直中间) ); firstSlide.setDuration(1000); // 设置动画时长(毫秒) firstSlide.setInterpolator(new AccelerateDecelerateInterpolator()); firstSlide.setStartOffset(300); // 延迟300ms开始 // 第二步:从右侧中间移动到屏幕中心 TranslateAnimation secondSlide = new TranslateAnimation( Animation.ABSOLUTE, screenWidthPx, // 起始X:屏幕最右 Animation.ABSOLUTE, screenWidthPx / 2f, // 目标X:屏幕水平中心 Animation.ABSOLUTE, screenHeightPx / 2f, // 起始Y:垂直中间 Animation.ABSOLUTE, screenHeightPx / 2f // 目标Y:垂直中心(Y轴不变) ); secondSlide.setDuration(1000); secondSlide.setInterpolator(new AccelerateDecelerateInterpolator()); // 让第二个动画在第一个动画结束后开始 secondSlide.setStartOffset(firstSlide.getDuration() + firstSlide.getStartOffset()); // 组合两个动画 AnimationSet animationSet = new AnimationSet(true); animationSet.addAnimation(firstSlide); animationSet.addAnimation(secondSlide); // 给目标View启动动画 yourTargetView.startAnimation(animationSet);
⚠️ 注意:TranslateAnimation是旧的补间动画,它只会改变View的绘制位置,View的实际触摸区域还是在原来的位置。如果需要View的物理位置也跟着移动,推荐使用下面的属性动画方案。
方法2:使用属性动画(推荐)
属性动画(ObjectAnimator)会真正改变View的布局参数,是Android官方推荐的现代动画方式:
Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); int screenWidthPx = size.x; int screenHeightPx = size.y; View yourTargetView = findViewById(R.id.your_view_id); // 先把View初始位置放到屏幕左下角 yourTargetView.setX(0f); // View的Y坐标是顶部的位置,所以要减去自身高度,才能让底部对齐屏幕底部 yourTargetView.setY(screenHeightPx - yourTargetView.getHeight()); // 第一步:从左下角移动到右侧中间 ObjectAnimator moveToRightMiddleX = ObjectAnimator.ofFloat(yourTargetView, "x", 0f, screenWidthPx - yourTargetView.getWidth()); // X轴到屏幕最右(减去View自身宽度避免超出) ObjectAnimator moveToRightMiddleY = ObjectAnimator.ofFloat(yourTargetView, "y", screenHeightPx - yourTargetView.getHeight(), (screenHeightPx / 2f) - (yourTargetView.getHeight() / 2f)); // Y轴到垂直中间(View中心对齐) AnimatorSet firstAnimatorSet = new AnimatorSet(); firstAnimatorSet.playTogether(moveToRightMiddleX, moveToRightMiddleY); firstAnimatorSet.setDuration(1000); firstAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); firstAnimatorSet.setStartDelay(300); // 第二步:从右侧中间移动到屏幕中心 ObjectAnimator moveToCenterX = ObjectAnimator.ofFloat(yourTargetView, "x", screenWidthPx - yourTargetView.getWidth(), (screenWidthPx / 2f) - (yourTargetView.getWidth() / 2f)); // X轴到水平中心 ObjectAnimator moveToCenterY = ObjectAnimator.ofFloat(yourTargetView, "y", (screenHeightPx / 2f) - (yourTargetView.getHeight() / 2f), (screenHeightPx / 2f) - (yourTargetView.getHeight() / 2f)); // Y轴保持中间 AnimatorSet secondAnimatorSet = new AnimatorSet(); secondAnimatorSet.playTogether(moveToCenterX, moveToCenterY); secondAnimatorSet.setDuration(1000); // 串行动画,先执行第一步再执行第二步 AnimatorSet totalAnimatorSet = new AnimatorSet(); totalAnimatorSet.playSequentially(firstAnimatorSet, secondAnimatorSet); totalAnimatorSet.start();
内容的提问来源于stack exchange,提问作者ZA BroadPeak
相关产品推荐
相关产品推荐

