【问题标题】:How to do interactive animation (translation) with Android如何用Android做互动动画(翻译)
【发布时间】:2012-03-16 22:56:14
【问题描述】:

我在 Android 中有一些 png 序列,我需要动画它们从屏幕顶部到底部的 x 和 y 位置平移。在动画发生时,我需要对象接收点击事件。

我知道这在 3.0 之前的 Android 版本中效果不佳,因为对象的 显示 与实际对象位于不同的位置,因此您不会在中间收到点击事件-动画(这是我需要的),因为您没有单击对象,仅在显示屏上。

我正在做这样的事情,动画看起来不错,但我从来没有进入点击处理程序:

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

3.0 之前的设备支持交互式动画的解决方法是什么?是否有一个自定义动画类将使用后台线程为对象的 x 和 y 位置设置动画?

——更新—— 我尝试使用 NineOldAndroid 的解决方案,动画看起来不错,但是在动画期间我没有收到 onclick 事件。这是我更新的代码。所以这在 ICS 上可以正常工作,但在 2.3 上不行 我做错了什么吗?还是 NineOldWorld 的解决方案实际上并没有改变引擎盖下的布局边距?

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

-- 更新 #2 --- 我也尝试了路径动画,但是在动画期间以及之后,我没有收到按钮单击事件。有谁知道我做错了什么?

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

【问题讨论】:

    标签: android android-animation


    【解决方案1】:

    你是对的,问题在于蜂窝之前,只有动画视图的视觉方面正在发生。

    这意味着除了做“视觉”动画之外,您还必须设置/动画动画视图的 frame/LayoutParams。

    对于Honeycomb 之前的设备,我发现http://nineoldandroids.com/ 对于收听动画非常有用,您可以使用它来适当地设置视图的LayoutParams,但还有其他示例,例如SO 上的这个:@ 987654322@

    【讨论】:

    • 我更新了我的答案,你能看到我在使用 noneoldandroid 的解决方案时做错了什么,为什么我没有收到点击事件?
    • NineOldAndroids 只是提供了一个统一的 API。不幸的是,它受到与使用本机视图动画时相同的限制。如果动画在屏幕上移动了某些东西,并且您希望它保持可点击状态,您将需要在动画完成后使用其LayoutParams 物理移动该对象。这很糟糕,但这是我们所拥有的一切。
    • 废话。我也那么认为。谢谢杰克。我将开始研究如何正确地做到这一点。如果您知道有任何样品可以做到这一点,我很乐意看到它们。
    • @Mo Kargas,仅供参考,看起来情况并非如此“对于蜂窝之前的设备,我发现 nineoldandroids.com 对于收听动画和适当设置视图的 LayoutParams 非常有用" 根据其创建者 Jake Wharton 的说法,它没有设置布局参数。
    • B-ryce - 我知道九个旧机器人无法处理实际的布局修改,我必须道歉,我在这一点上不清楚。但它提供了一个很好的 API 来监听动画 - 是的,你仍然必须手动处理 Jake 提到的 LayoutParam 修改,但你可以使用九提供的监听器来这样做。
    【解决方案2】:

    这就是我最终做的,效果很好。

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

    这是我的课:

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

    【讨论】: