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

Android 将动画视图保持在最终动画位置,android,animation,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

因此,我正在使用动画设置视图的动画:

<?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>
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);
这将为视图设置动画,视图保持在动画位置-这正是我想要实现的。
但是,所有控件实际上都保持在它们的位置。即使是你的布局也只有25%的底部可见,其余75%的屏幕看起来是空的,如果我点击那个空屏幕区域,然后点击按钮(这是b4动画)。如果设置了xml动画,也会发生同样的情况

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,因为它与父项或类似项匹配。它不会返回真正的像素,而是一些表示常量的值!看来我有两个游戏可以玩
.getViewTreeObserver().addOnGlobalLayoutListener

好的,我通过getViewTreeObserver()获得了rootWrapper的实际高度。现在使用公式
rootlp.topMargin=-rootlp.height*75/100我遇到了更多问题。
1)在动画视图向上移动后(由于设置了LP)。
2) 动画视图包含的控件(必须随父视图向上移动的按钮)实际上保持在其位置(它们不可见但可单击)!从视觉上看,这些控件随着动画视图向上移动,我够不到它(它离开屏幕)。但若我点击动画触发之前它们所在的区域,相应的onClick()就会触发!多有趣啊
更新3

我终于实现了我的目标!问题在于移动视图的子容器。我在想,如果我移动一些视图,那么它的所有子视图也都在移动。但情况并非如此,在动画完成后,我不得不手动移动子视图来修复鬼影按钮。

< P>请考虑<强> SETFILITEX(布尔);strong>将其设置为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);
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;
}
使用API 14及更高版本提供的ViewPropertyAnimator可以更轻松地完成此操作:

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

或考虑<强>动画监听器在动画完成后获取LayOutPARAM:

<?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>
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动画中的百分比值是相对于动画视图的尺寸(例如宽度和高度)的。因此,您只需要使用视图的宽度和高度属性(取决于您使用x或y动画来获得以像素为单位的实际动画距离)

例如:

您的视图的宽度为400像素。您的动画将x属性从0%设置为75%,这意味着您的视图将向右移动300像素(400*0.75)。因此,在animationend()上,将LayoutParams.leftMargin设置为300,您的视图将具有所需的位置。

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

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

只要简单地作为LibraryProject导入就可以了。

我发现简单地将fillEnabled和fillAfter设置为TRUE并不能解决涉及单击/触摸监听器之类的问题。将“已启用填充”和“之后填充”设置为true可确保在正确的最终位置绘制视图的像素。但是,假设正在设置动画的视图有一个关联的onclick侦听器。在视图的新可见位置单击该视图将不起任何作用,但是在视图原来的位置单击屏幕将触发onClick

下面是一个如何绕过此问题的示例:

假设我们有一个设置了onClickListener的视图。还假设视图边界为0,0,0,0(左、上、右、下)。 假设现在我们希望将视图向右移动200。下面的代码将演示如何将要绘制的像素和基础视图对象移动到正确的位置,从而从正确的位置调整要调用的onClick

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

为什么要在动画之后获取LayoutParams?你想让视图保持在动画位置吗?是的,正是我想要的2do。然后查看我的anser并使用setFillAfter();塔克斯!anim.setFillAfter(真);这样做的技巧,但所有的控制保持几乎(不可见)在他们的位置。请查看我的更新1。请参阅animationlistener,特别是我回答中的animationEnd方法:)您可以获取layoutParams并将其设置为EquatelyYeah,但是如何知道生成NewTopMargin的动画?这是我问题的一部分,因为我在提问之前已经尝试在onAnimationEnd中设置LP,但仍然坚持设置值。thanx再次尝试rootlp.topMargin=-rootlp.height*100/75;和rootWrapper.setLayoutParams(rootlp);但是运气不好-隐形控制还在那里…你说的隐形控制还在那里是什么意思?你能在你的问题中发布你的代码吗?就像我在问题中提到的,我已经试过了。这导致了我的Q@BiGGZ中也描述了一些关于幽灵控制的问题。你的意思是我需要添加更多细节吗?顺便说一下,我正在尝试,但它不起作用。我的触摸事件仍被发送到旧位置。而且
lp
对象在任何地方都没有被使用,老实说,我这么做已经有一段时间了,但我强烈建议从动画开始使用整个范例。我建议改用ObjectAnimators。这个API远比这个旧的动画好。