3

I have some png sequences in Android, that I need to animation their x and y postion translation from the top to the bottom of the screen. While the animation is occurring, I need the objects to receive click events.

I understand this doesn't work really well in Android version before 3.0, since the display of the object is in a different place than the actual object so you don't get the click events mid-animation (which is what I need) since you aren't clicking on the object, only on the display.

I'm doing something like this, and the animation looks fine, but I never get into the click handler:

Animation animation = new TranslateAnimation(0, 20,0, 300);
animation.setDuration(1000);
ticket.startAnimation(animation);

ticket.startAnimation(animation);

ticket.setOnClickListener(new OnClickListener() {
    public void onClick(View view) {
            //I don't get into this click event during animation
        view.setVisibility(View.GONE);
    }
});

What is the workaround to support interactive animations for devices before 3.0? Is there a custom animation class out there that will use a background thread to animate the x and y position of an object?

--update --- I tried using NineOldAndroid's solution, and the animation looks fine, but I'm not getting the onclick events during the animation. Here is my updated code. So this works fine on ICS, but not on 2.3 Am I doing something wrong? or is the NineOldWorld's solution not actually changing the layout margins under the hood?

ImageView ticket = new ImageView(myActivity);
            ticket.setImageResource(R.drawable.ticket);
            ticket.setVisibility(View.INVISIBLE);
            ticketHolder.addView(ticket);
            ValueAnimator animation = ObjectAnimator.ofFloat(ticket, "y", 
                    -200f, ticketHolder.getHeight());
            animation.setDuration(3000);
            animation.start();
            animation.setStartDelay(i*1000);
            animationsMap.put(animation, ticket);

            ticket.setOnClickListener(new OnClickListener() {
                public void onClick(View view) {
                    view.setVisibility(View.GONE);
                }
            });

            animation.addListener(new AnimatorListenerAdapter() {
                public void onAnimationEnd(Animator animation) {
//                    tickets.remove(((ObjectAnimator)animation).getTarget());
                    ImageView t = (ImageView) ((ObjectAnimator) animation).getTarget();
                    t.setVisibility(View.GONE);
                    animationsMap.remove(animation);
                    if(animationsMap.size() == 0){
                        ticketsAnimating = false;
                        scrim.setVisibility(View.VISIBLE);
                    }

                }
                @Override
                public void onAnimationStart(Animator animation){
                    ImageView t = (ImageView) ((ObjectAnimator) animation).getTarget();
                    t.setVisibility(View.VISIBLE);
                }
            });

-- Update #2 --- I also tried the path animation, but during the animation, and after, I'm not getting button click events. Anyone know what I'm doing wrong?

mButton = (Button) findViewById(R.id.delete_me);
mButtonProxy = AnimatorProxy.wrap(mButton);

// Set up the path we're animating along
AnimatorPath path = new AnimatorPath();
path.moveTo(0, 0);
path.lineTo(0, 300);
path.curveTo(100, 0, 300, 900, 400, 500);

// Set up the animation
final ObjectAnimator anim = ObjectAnimator.ofObject(this, "buttonLoc",
        new PathEvaluator(), path.getPoints().toArray());
anim.setDuration(10000);

mButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("united", "button clicked");
        anim.start();
    }
});
b-ryce
  • 5,752
  • 7
  • 49
  • 79

2 Answers2

4

You're right, the issue is that pre-Honeycomb, only the visual aspect of your animating view is occurring.

This means that in addition to doing the "visual" animation, you also have to set/animate the frame/LayoutParams of the animated view.

For pre-Honeycomb devices, I find http://nineoldandroids.com/ very useful for listening to an animation which you can use for setting the LayoutParams of the view appropriately, but there are other examples as well, such as this one on SO: https://stackoverflow.com/a/3952933/429047

Community
  • 1
  • 1
Mo Kargas
  • 1,000
  • 7
  • 24
  • I updated my answer, can you see what I'm doing wrong with the noneoldandroid's solution as to why I'm not getting click events? – b-ryce Mar 07 '12 at 16:02
  • 13
    NineOldAndroids simply provides a unified API. Unfortunately it suffers from the same limitations as when you were using native view animation. If the animation moves something on the screen and you want it to remain clickable you will need to physically move the object once the animation completes using its `LayoutParams`. It sucks, but it's all we've got. – Jake Wharton Mar 07 '12 at 17:38
  • Crap. Thats what I thought. Thanks Jake. I'll start looking into how to do this correctly. If you know of any samples out there that do this, I'd love to see them. – b-ryce Mar 07 '12 at 18:19
  • @Mo Kargas, FYI, it looks like this isn't the case "For pre-Honeycomb devices, I find http://nineoldandroids.com/ very useful for listening to an animation and setting the LayoutParams of the view appropriately" According to its creator, Jake Wharton, it doesn't set the layout params. – b-ryce Mar 07 '12 at 18:23
  • B-ryce - I know nine old androids doesn't handle the actual layout modification, I'm must apologize that I was unclear on that point. But it provides a nice API for listening to the animation - yes you still have to manually handle the LayoutParam modifications as Jake mentions, but you can use the listeners that nine provides to do so. – Mo Kargas Mar 07 '12 at 20:22
  • @JakeWharton I tried your solution it worked but still perfect, after adding setLayoutParams() in onAnimationEnd(), the animation looks is not showing, code snippet as following [my code](https://gist.github.com/anonymous/9593531) , can you please figure me out if i did anything wrong, thanks. – Weibo Mar 17 '14 at 03:37
1

This is what I ended up doing, which works pretty well.

MyTranslateAnimation animation = new MyTranslateAnimation(ticket, 10, 100, -500, ticketHolder.getHeight());

And here is my class:

public class MyTranslateAnimation extends Animation {
        private float fromXDelta;
        private float fromYDelta;
        private float toXDelta;
        private float toYDelta;
        private View view;

        public MyTranslateAnimation(View view, float fromXDelta,
                float toXDelta, float fromYDelta, float toYDelta) {
            this.view = view;
            this.fromXDelta = fromXDelta;
            this.toXDelta = toXDelta;
            this.fromYDelta = fromYDelta;
            this.toYDelta = toYDelta;
        }

        @Override
        protected void applyTransformation(float interpolatedTime,
                Transformation t) {
            Log.d("united", "time " + interpolatedTime);
            float newX = (toXDelta - fromXDelta) * interpolatedTime;
            float newY = (toYDelta - fromYDelta) * interpolatedTime;
            LayoutParams p = (LayoutParams) view.getLayoutParams();
            p.leftMargin = (int) newX;
            p.topMargin = (int) newY;
            if (interpolatedTime > 0.0 && view.getVisibility() == View.GONE) {
                view.setVisibility(View.VISIBLE);
            }
            view.requestLayout();
        }
    }
b-ryce
  • 5,752
  • 7
  • 49
  • 79