Button is not clickable after TranslateAnimation
Asked Answered
P

4

18

I'm trying to move button (with animation) upon click. I want it to move 100 pixels to the bottom on first click, 100 pixels up on second, 100 pixels to the bottom on third and so on. I have simple layout file (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" />

My launching activity is as follows:

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;
        }
    });
}
}

When I press the button, I can see it moving to the bottom. But when I press it for the second time, nothing happens. I have to click to initial rectangle of the button to begin animation again. It seems like button is drawn as expected, but actual view is remained on the same position. I want to know how I can move a view entirely, not just its visual part. Besides, I use Toast.maketext.show to ensure that coordinates of the button aren't changed from click to click.

Petulance answered 30/1, 2012 at 17:10 Comment(1)
So pre-HoneyComb, how can we solve the problem of non-clickable Buttons after a Translation Animation for moving child's, say the case of Cover Flow whose child's are skewed using animation. I have tried using the Touch-delegate method, but its seems to be not working, can you please suggest a way to solve this.Melanesian
A
10

Yes, this is normal behavior. This is because animation just rerenders View's pixels, but it's position on the display remains the same. If you want to relocate your View to the place where your animation ends, you need to call View.layout() method and pass there 4 parameters, which describe Views new position on it's layout. Keep in mind that View.layout() gets params relative to Views parent.

Amarillo answered 30/1, 2012 at 17:34 Comment(1)
Using layout() is not the right solution, because i can be called by the framework (by default values) and your position got reset again to default's!.Correct solution is setting LayoutParams to actually move the view to new position.Propose
R
45

There is an easier way worth mentioning. One can use the View.animate() method which also moves the clickable elements:

v.animate().translationY(100).start(); // move away
v.animate().translationY(0).start(); // move back
Roughneck answered 6/1, 2016 at 10:54 Comment(5)
Simple and Easy! Best Answer! Thank u!Barney
I'm using mBtnCompare.animate().translationY(-15).alpha(1).setDuration(200).start(); but clickable area doesn't move.Nowell
I wich I could give 100 points for this answer. I was messing with animation xmls for just nothing for hours before seeing your answer. god bless you my friend.Sanctitude
This is not a solution to this question. Please read the question again.Telson
using animate() does work. However I ran into an added layer of headache that took some time to figure out. If you move the view outside of its parent's bounds (you'll have to set the parent's clipChilden to false), the button will not work. Keep this in mind when designing your layout.Proserpina
A
10

Yes, this is normal behavior. This is because animation just rerenders View's pixels, but it's position on the display remains the same. If you want to relocate your View to the place where your animation ends, you need to call View.layout() method and pass there 4 parameters, which describe Views new position on it's layout. Keep in mind that View.layout() gets params relative to Views parent.

Amarillo answered 30/1, 2012 at 17:34 Comment(1)
Using layout() is not the right solution, because i can be called by the framework (by default values) and your position got reset again to default's!.Correct solution is setting LayoutParams to actually move the view to new position.Propose
P
3

View.layout() really works, thanks a lot, teoREtik. Here I provide working variant, which moves the button itself (hope it will be useful for somebody):

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;
        }
    });
}

We have to invoke View.layout() only when animation is finished, so we need to use AnimationListener.onAnimationEnd. In order to be able to specify button and modifierY, I created my custom AnimationListener, which receives button and modifierY in constructor:

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) {}

}
Petulance answered 31/1, 2012 at 9:19 Comment(3)
By the way, well, perhaps only in my observation, but OnAnimationEnd() is called before the actual end of animation. I had a lot of problems with it when I tried to combine repositioning of the View with AlphaAnimationAmarillo
By the way, I've come across another problem while repositioning views - View.layout looses effect upon UI update. I described the problem in this topic - #9080773, maybe you can help.Petulance
I just tried to fix my layout using view.layout(...) in onAnimationEnd and indeed it gets reverted back to its orginal values and thus does not work.Roane
H
2

An easy solution is to add padding in the onAnimationEnd function:

 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);


}

where i = (ImageView) findViewById(R.id.imgAMD);

Heighho answered 3/8, 2012 at 13:53 Comment(1)
What is the goal of setting i.setPadding(x,y,0,0) twice ?Octuple

© 2022 - 2024 — McMap. All rights reserved.