22

So I'm animating a view using 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>

It does visually what I want but I also I want to freeze result of this animation. Like I need somehow to get resulting layout parameters (or something else?) after animation and set it to layout. Assume layout Y-coord is changing from 0 to 100 but I don't really know what was starting coords and what are resulting coords. I need to get resulting coords and set it to the layout cuz if wouldn't do so layout returns back to its initial position after animation but I need to make it stay in new position instead of returning back. Also I need 2.3.x compatible solution.
UPDATE 1
I also tried NineOldAndroids:

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

this animates the view and view stays at animated position - thats exactly what I want to achieve.
However all controls stays at their positions virtually. Even thou layout is only visible by 25% of its bottom part and 75% of rest screen looks empty if I tap that empty screen area then button's (which was there b4 animation) onClick triggered. The same happens with xml-animtaions if set

animation.setFillAfter(true); 

How to fix that issue? All controls has to move with the view.
UPDATE 2
The code:

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

I got the problem - rootlp.height returns 0 cuz its like MATCH_PARENT or like. It wont return the REAL pixels but some value representing some constant! So it looks like I have 2 play with .getViewTreeObserver().addOnGlobalLayoutListener.
Ok, I got the real height of rootWrapper via getViewTreeObserver(). And now using the formula rootlp.topMargin = -rootlp.height*75/100; I'm getting even more issues.
1) After animation View moves up additionally (due to setting LP).
2) Controls that animated View contains (buttons which has to move up with the parent View) stays at their positions virtually (they are invisible but clickable)! Visually those controls are moved up with the animated View and I can't reach it (it goes off the screen). But if I tap area where they was before animation corresponding onClick() triggers! What a fun!
UPDATE 3
Finally I had achieved my goal! The problem was with moving View's child containers. I was thinking that if I move some View then all of its child views are also moving. But thats not the case and I was had to move child views manually after animation completes to fix ghost buttons.

4

3 回答 3

54

请考虑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 动画中的百分比值与动画视图的尺寸(例如宽度和高度)相关。因此,您只需要使用视图的宽度和高度属性(根据天气您使用 x 或 y 动画来获取以像素为单位的实际动画距离)。

例如:

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

于 2013-08-16T08:55:25.730 回答
2

我发现当涉及点击/触摸监听器之类的事情时,简单地将 fillEnabled 和 fillAfter 设置为 TRUE 并不能解决问题。将启用填充和填充后设置为真只是确保视图的像素在正确的最终位置绘制。但是,假设正在动画的视图有一个与之关联的 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;
}
于 2015-07-06T15:40:03.673 回答
0

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

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

于 2013-08-16T12:36:33.923 回答