Android动画问题:第二个动画启动时跳至屏幕顶部而非前一位置
这问题我之前也碰到过!核心原因是补间动画(不管是Java代码写的还是XML定义的)的“视觉欺骗”特性——它只会临时改变View的显示位置,不会修改View的真实布局参数或属性值。第一个动画结束后,View的“真实位置”还是它最初的位置(大概率是屏幕顶部),当第二个动画启动时,系统会先把View重置到这个真实位置,再执行动画,就出现了你看到的跳顶现象。
下面给你几个靠谱的解决方案,按推荐程度排序:
1. 改用属性动画(最稳妥)
属性动画(比如ObjectAnimator)会直接修改View的实际属性(比如translationX、translationY),动画结束后属性值会保留,完全不会有位置重置的问题。把你的第一个Java动画换成属性动画试试:
// 假设你原来的动画是让气球从(startX, startY)飘到(targetX, targetY) ObjectAnimator floatAnimX = ObjectAnimator.ofFloat(balloonImageView, "translationX", startX, targetX); ObjectAnimator floatAnimY = ObjectAnimator.ofFloat(balloonImageView, "translationY", startY, targetY); AnimatorSet floatAnimatorSet = new AnimatorSet(); floatAnimatorSet.playTogether(floatAnimX, floatAnimY); floatAnimatorSet.setDuration(1500); // 替换成你原来的动画时长 floatAnimatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) {} @Override public void onAnimationEnd(Animator animation) { // 直接启动第二个动画,不需要额外处理位置 Animation bounceAnim = AnimationUtils.loadAnimation(context, R.anim.bounce); balloonImageView.startAnimation(bounceAnim); } @Override public void onAnimationCancel(Animator animation) {} @Override public void onAnimationRepeat(Animator animation) {} }); floatAnimatorSet.start();
2. 补间动画结束后手动固定View位置
如果你坚持要用补间动画,那必须在第一个动画结束后,手动把View的真实位置更新到动画结束后的显示位置。在onAnimationEnd回调里这么做:
firstAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { // 获取动画结束后View的最终显示坐标 int finalLeft = (int) (balloonImageView.getLeft() + firstAnimation.getTranslateX()); int finalTop = (int) (balloonImageView.getTop() + firstAnimation.getTranslateY()); int finalRight = (int) (balloonImageView.getRight() + firstAnimation.getTranslateX()); int finalBottom = (int) (balloonImageView.getBottom() + firstAnimation.getTranslateY()); // 手动设置View的真实布局位置 balloonImageView.layout(finalLeft, finalTop, finalRight, finalBottom); // 启动第二个动画 Animation bounceAnim = AnimationUtils.loadAnimation(context, R.anim.bounce); balloonImageView.startAnimation(bounceAnim); } @Override public void onAnimationRepeat(Animation animation) {} });
另外,你也可以给第一个动画设置firstAnimation.setFillAfter(true),但这个只是让View保持动画结束后的视觉状态,不会修改真实布局参数——如果后续父布局发生重新测量/布局,View还是会跳回初始位置,所以手动调用layout()更可靠。
3. 检查第二个动画的XML配置
最后,确认你的bounce.xml没有硬编码绝对位置的问题。比如如果你的动画是translate类型,要确保使用相对当前位置的百分比值,而不是绝对像素值:
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:fromYDelta="0%" <!-- 相对于当前位置的0% --> android:toYDelta="10%" <!-- 相对于当前位置向下10% --> android:interpolator="@android:anim/bounce_interpolator"/>
如果用了android:fromYDelta="0px"这种绝对像素值,动画会从View的初始位置(顶部)开始,自然会出现跳顶现象。
内容的提问来源于stack exchange,提问作者DevOpsSauce

