修改ImageView的X、Y坐标后旋转动画异常问题求助
嘿,我明白你遇到的麻烦了——刚把image2移到image1的位置就启动旋转动画,结果它在屏幕上乱跑,但单独跑动画又没问题对吧?这其实是Android两种位置/动画机制的兼容性问题导致的,我给你拆解下原因和解决办法:
问题根源
你用的setX()/setY()是修改视图的平移偏移量(本质是改translationX/translationY属性),属于视图的真实位置调整;但你用的传统补间动画(Animation类)是基于视图在布局里的原始坐标来计算动画的,包括旋转的基准点(pivotX/pivotY)。当你刚改完平移位置就立刻启动动画,动画会同时叠加原始位置的偏移和平移后的位置,结果就导致视图乱跑了。
两种解决方案
方案1:改用属性动画(强烈推荐)
属性动画(ObjectAnimator)是直接修改视图的实际属性,和setX()/setY()的位置修改完全兼容,不会有坐标系冲突的问题。把你的Java代码换成下面这样:
image1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 先把image2移到目标位置 image2.setX(image1.getX()); image2.setY(image1.getY()); // 创建旋转属性动画,从0度转到-50度 ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(image2, "rotation", 0f, -50f); rotateAnim.setDuration(1000); // 旋转基准点设为视图中心(默认就是50%,这句可以省略,写出来更清楚) image2.setPivotX(image2.getWidth() / 2f); image2.setPivotY(image2.getHeight() / 2f); rotateAnim.start(); } });
这样就不需要依赖XML动画文件了,动画会基于image2当前的真实位置执行旋转,绝对不会乱跑。
方案2:用补间动画的话先等布局刷新
如果你想继续用XML里的补间动画,那得先让image2的位置修改生效并完成布局刷新,再启动动画。可以用post()方法延迟一下,让系统有时间更新布局:
image1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { image2.setX(image1.getX()); image2.setY(image1.getY()); // 让视图先完成位置更新,再在主线程队列里启动动画 image2.post(new Runnable() { @Override public void run() { Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.myanim); image2.startAnimation(animation); } }); } });
或者你也可以不用setX()/setY(),而是通过修改LayoutParams来设置image2的位置——这样是从布局层面修改位置,补间动画的坐标系就会和布局位置一致:
image1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 这里假设父布局是RelativeLayout,根据你的实际布局类型调整 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) image2.getLayoutParams(); params.leftMargin = (int) image1.getX(); params.topMargin = (int) image1.getY(); image2.setLayoutParams(params); // 现在启动动画就没问题了 Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.myanim); image2.startAnimation(animation); } });
总结
优先选属性动画,它是Android 3.0之后的标准方案,更灵活还能避开传统补间动画的各种坑。如果一定要用补间动画,记得让位置修改先完成布局刷新再启动动画哦。
内容的提问来源于stack exchange,提问作者Niv

