TranslateAnimation后按钮无法点击

18

我正在尝试在点击按钮时移动它(带有动画效果)。 我希望第一次点击后它向下移动100像素,第二次向上移动100像素,第三次再向下移动100像素,以此类推。 我有一个简单的布局文件(main.xml):

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Press to begin animation" />

我的启动活动如下:

public class TestActivity extends Activity {
public final String TAG="TestActivity";
boolean toTop=false;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main); 
    Button b=(Button)findViewById(R.id.button);
    b.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            Toast.makeText(TestActivity.this, "left="+v.getLeft()+"\nright="+v.getRight(), Toast.LENGTH_SHORT).show();

            Animation translateAnimation;
            if(toTop) translateAnimation=new TranslateAnimation(0, 0, 0, -100); 
            else translateAnimation=new TranslateAnimation(0, 0, 0, 100);
            translateAnimation.setDuration(1000);
            translateAnimation.setFillEnabled(true);
            translateAnimation.setFillAfter(true);

            v.startAnimation(translateAnimation);
            toTop=!toTop;
        }
    });
}
}
当我按下按钮时,我可以看到它向底部移动。但是当我第二次按下它时,什么也不发生。我必须点击按钮的初始矩形才能再次开始动画。似乎按钮按预期绘制,但实际视图仍停留在同一位置。我想知道如何整体移动一个视图,而不仅仅是它的可视部分。此外,我使用Toast.maketext.show确保从一次点击到另一次点击按钮的坐标未发生改变。

那么在HoneyComb之前,我们如何解决移动子项的翻译动画后无法点击按钮的问题,比如Cover Flow的子项使用动画倾斜的情况。我尝试过使用Touch-delegate方法,但似乎不起作用,请您提供解决方法。 - Sri Krishna
4个回答

45

还有一个值得一提的更简单的方法。可以使用View.animate()方法,该方法也会移动可点击的元素:

v.animate().translationY(100).start(); // move away
v.animate().translationY(0).start(); // move back

1
简单易懂!最佳答案!谢谢! - John
2
我正在使用 mBtnCompare.animate().translationY(-15).alpha(1).setDuration(200).start(); 但可点击区域不会移动。 - Mahdi Moqadasi
2
我希望我能为这个答案给予100分。在看到你的答案之前,我浪费了几个小时来处理动画XML,但最终却毫无进展。上帝保佑你,我的朋友。 - smoothumut
这不是该问题的解决方案。请再次阅读问题。 - user5832543
使用animate()确实有效。但是我遇到了一个额外的麻烦层,花了一些时间才弄清楚。如果您将视图移动到其父级范围之外(您必须将父级的clipChilden设置为false),则按钮将无法正常工作。在设计布局时请记住这一点。 - dollardime

10

是的,这是正常的行为。这是因为动画只重新渲染了View的像素,但它在屏幕上的位置仍然保持不变。如果您想将View重新定位到动画结束的位置,您需要调用View.layout()方法并传递4个参数,这些参数描述了View在布局中的新位置。请记住,View.layout()获取相对于View父级的参数。


6
使用 layout() 不是正确的解决方案,因为默认情况下框架可能会调用它(使用默认值),这将再次将您的位置重置为默认值!正确的解决方案是设置 LayoutParams 来实际移动视图到新位置。 - Muhammad Babar

3

View.layout()的确有用,非常感谢teoREtik。我提供了一个工作变量,它可以移动按钮本身(希望对某些人有用):

public class TestActivity extends Activity {
public final String TAG="TestActivity";
boolean toTop=false;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main); 
    Button b=(Button)findViewById(R.id.button);
    b.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            int modifierY;
            if(toTop) modifierY=-100; 
            else modifierY=100;
            Animation translateAnimation=new TranslateAnimation(0, 0, 0, modifierY);
            translateAnimation.setDuration(1000);
            translateAnimation.setFillEnabled(true);
            MyAnimationListener listener=new MyAnimationListener(v, modifierY,TestActivity.this);
            translateAnimation.setAnimationListener(listener);

            v.startAnimation(translateAnimation);
            toTop=!toTop;
        }
    });
}

当动画完成后,我们才需要调用View.layout()方法,因此需要使用AnimationListener.onAnimationEnd。为了能够指定按钮和modifierY,我创建了自定义的AnimationListener,在构造函数中接收按钮和modifierY:

public class MyAnimationListener implements AnimationListener{
View mView;
int mModifier;
Context mContext;

public MyAnimationListener(View v, int modifier, Context c){
    mView=v;
    mModifier=modifier;
    mContext=c;
}
public void onAnimationEnd(Animation animation) {
    int[] pos={mView.getLeft(),mView.getTop()+mModifier,mView.getRight(),mView.getBottom()+mModifier};
    mView.layout(pos[0],pos[1],pos[2],pos[3]);
    Toast.makeText(mContext, "left="+mView.getLeft()+"\ntop="+mView.getTop(), Toast.LENGTH_SHORT).show();
}

public void onAnimationRepeat(Animation animation) {}

public void onAnimationStart(Animation animation) {}

}

1
顺便说一句,也许只是我的观察,但 OnAnimationEnd() 在实际动画结束之前就被调用了。当我尝试将 View 的重新定位与 AlphaAnimation 结合使用时,我遇到了很多问题。 - teoREtik
顺便提一下,我在重新定位视图时遇到了另一个问题 - View.layout 在 UI 更新后失效。我在这个主题中描述了这个问题 - http://stackoverflow.com/questions/9080273/view-layout-works-until-next-ui-update,也许你可以帮忙解决。 - Eugene Chumak
我刚刚尝试在onAnimationEnd中使用view.layout(...)来修复我的布局,但实际上它会被恢复到原始值,因此无法起作用。 - slott

2

一个简单的解决方案是在onAnimationEnd函数中添加padding:

 public void moveAnimation() {

    move = new TranslateAnimation(Pos-50, 0, 0, 0);
    Pos += 50.0;
    move.setDuration(1500);
    move.setFillAfter(true);
     move.setAnimationListener(new AnimationListener(){

            @Override
            public void onAnimationEnd(Animation arg0) {

                int x=(int) (Pos-50),y=0; 
                i.setPadding(x,y,0,0);
                x+=50; y+=0;
                i.setPadding(x,y,0,0);
            }

            @Override
            public void onAnimationRepeat(Animation arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationStart(Animation arg0) {
                // TODO Auto-generated method stub

            }

        });


    i.startAnimation(move);


}

此代码意为:将id为 imgAMD 的 ImageView 组件赋值给 i 变量。


设置 i.setPadding(x,y,0,0) 两次的目标是什么? - AnthoPak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接