在最终动画位置保持动画视图

时间:2013-08-16 08:47:55

标签: android animation

所以我使用动画制作视图动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >

    <translate
        android:duration="1000"
        android:fromYDelta="0%"
        android:toYDelta="-75%" />

</set>

它在视觉上做我想要的但是我也想冻结这个动画的结果。就像我需要以某种方式在动画之后获得结果布局参数(或其他东西?)并将其设置为布局。假设Y-coord的布局从0变为100但我真的不知道什么是起始坐标和什么是产生的坐标。我需要得到结果的coords并将其设置为布局cuz如果不这样做布局返回到动画后的初始位置但我需要让它保持在新位置而不是返回。我还需要兼容2.3.x的解决方案 更新1
我也试过NineOldAndroids:

ObjectAnimator.ofFloat(rootWrapper, "translationY", -rootWrapper.getHeight()*75/100).start();

这会使视图和视图保持动画位置的动画效果 - 这正是我想要实现的目标。
但是所有控件都会虚拟地保持在它们的位置。如果我点击那个空屏幕区域然后按钮(那里有b4动画)onClick触发,即使你的布局只有25%的底部可见,75%的休息屏幕看起来是空的。如果设置

,xml-animtaions也会发生同样的情况
animation.setFillAfter(true); 

如何解决这个问题?所有控件都必须随视图移动 更新2
代码:

    public void showAbout(){

        final Animation animShow = AnimationUtils.loadAnimation(this, R.anim.about_in_from_bottom);
        animShow.setFillAfter(true); 

        //ObjectAnimator.ofFloat(rootWrapper, "translationY", -rootWrapper.getHeight()*75/100).start();

        animShow.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {}

            @Override
            public void onAnimationEnd(Animation animation) {
                LinearLayout.LayoutParams rootlp = (LinearLayout.LayoutParams) rootWrapper.getLayoutParams();
                Log.i(this,"rootlp: h: "+rootlp.topMargin+ " / w: "+rootlp.bottomMargin);
                rootlp.topMargin = -rootlp.height*75/100;
                rootWrapper.setLayoutParams(rootlp);
            }
        });

        rootWrapper.startAnimation(animShow);
    }

我遇到了问题 - rootlp.height返回0因为它像MATCH_PARENT一样。它不会返回REAL像素,但某些值代表一些常数!所以看起来我和.getViewTreeObserver().addOnGlobalLayoutListener玩了2次 好的,我通过getViewTreeObserver()得到了rootWrapper的真正高度。现在使用公式rootlp.topMargin = -rootlp.height*75/100;我会遇到更多问题。
1)动画后视图向上移动(由于设置LP)。
2)动画视图包含的控件(必须与父视图一起向上移动的按钮)几乎停留在它们的位置(它们是不可见但可点击的)!在视觉上,这些控件随着动画视图向上移动,我无法触及它(它离开屏幕)。但是如果我在动画对应的onClick()触发器之前点击它们所在的区域!真有趣! 更新3
最后我实现了目标!问题在于移动View的子容器。我想如果我移动一些View,那么它的所有子视图也在移动。但事实并非如此,我不得不在动画完成后手动移动子视图来修复鬼按钮。

3 个答案:

答案 0 :(得分:47)

请考虑 setFillAfter(boolean); 将其设置为true将使视图保持在动画位置。

Animation anim = new TranslateAnimation(0, 0, 0, 100);

// or like this
Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation_name);

anim.setFillAfter(true); 
anim.setDuration(1000);

使用API​​ 14及更高版本提供的 ViewPropertyAnimator 可以更轻松地完成此操作:

int animationpos = 500;
View.animate().y(animationpos).setDuration(1000); // this will also keep the view at the animated position

或者考虑使用 AnimationListener 来完全获取动画后的LayoutParams:

anim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {}

            @Override
            public void onAnimationRepeat(Animation animation) {}

            @Override
            public void onAnimationEnd(Animation animation) {
                  // get layoutparams here and set it in this example your views 
                  // parent is a relative layout, please change that to your desires

                  RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) View.getLayoutParams();
                  lp.topMargin = yournewtopmargin // use topmargin for the y-property, left margin for the x-property of your view
                  View.setLayoutParams(lp);
                }
            });

    View.startAnimation(anim);

<强>更新

  

如何知道视图移动了多少像素,具体取决于   动画的百分比值?

.xml动画中的百分比值相对于动画视图的尺寸(例如宽度和高度)。因此,您只需要使用您的视图的宽度和高度属性< / strong>(取决于天气你使用x或y动画来获得实际的动画距离,以像素为单位)。

例如:

您的视图宽度为400像素。您的动画将x属性设置为0%到75%,这意味着您的视图将向右侧移动300像素(400 * 0.75)。所以onAnimationEnd(),将LayoutParams.leftMargin设置为300,你的View将具有所需的位置。

答案 1 :(得分:2)

我发现简单地将fillEnabled和fillAfter设置为TRUE并不能解决涉及点击/触摸侦听器之类的问题。设置填充启用并填充后为true只是确保视图的像素在正确的最终位置是DRAWN。但是,假设正在设置动画的视图具有与之关联的onclick侦听器。在新的可见位置单击视图将不执行任何操作,但是在视图最初的位置单击屏幕将触发onClick。

以下是如何解决此问题的示例:

假设我们有一个设置了onClickListener的视图。假设视图边界为0,0,0,0(左,上,右,下)。 假设现在我们希望将视图向右移动200.以下代码将演示如何以将要绘制的像素和基础视图对象移动到正确位置的方式执行此操作,从而将onClick调整为从正确的位置打电话。

private Animation generateMoveRightAnimation() {
    final Animation animation = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 200,
            Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0);
    animation.setDuration(300);
    animation.setFillAfter(true);
    animation.setFillEnabled(true);

    animation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) view.getLayoutParams();
            // change the coordinates of the view object itself so that on click listener reacts to new position
            view.layout(view.getLeft()+200, view.getTop(), view.getRight()+200, view.getBottom());
            repeatLevelSwitch.clearAnimation();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

    return animation;
}

答案 2 :(得分:0)

您可以根据需要使用NineOldAndroid代理库来使用ObjectAnimator。它支持较低的api级别,并使用本机库来获得更新的api级别。

只需简单地导入为LibraryProject,它就会很好。