Animate a view from one Layout to other Layout

2020-05-21 05:15发布

问题:

Check attached image for easy explanation.

Translate animation works but it animates inside the same view. I want view to fly out from one layout to other.

I tried this from another answer here. (Animates in same layout)

public class Animations {
        public Animation fromAtoB(float fromX, float fromY, float toX, float toY, int speed){


            Animation fromAtoB = new TranslateAnimation(
                    Animation.ABSOLUTE, //from xType
                    fromX,
                    Animation.ABSOLUTE, //to xType
                    toX,
                    Animation.ABSOLUTE, //from yType
                    fromY,
                    Animation.ABSOLUTE, //to yType
                    toY
            );

            fromAtoB.setDuration(speed);
            fromAtoB.setInterpolator(new AnticipateOvershootInterpolator(1.0f));

            return fromAtoB;
        }

回答1:

I recently did animation of a similar kind using Animators. In general, views will not display themselves outside of their parents' boundaries, the view will be cut by it's parent's boundaries. That's why, the trick is to place a new view (shuttleView) on top of the origin view (fromView) that you want to animate, align them, and animate scaling/translation of shuttleView into a target view (toView).

This solution supports both scaling and translation, here is sample: https://www.dropbox.com/s/iom95o93076h52f/device-2016-06-03-111557.mp4?dl=0

Here is the code:

activity_main.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:layout_alignParentTop="true"
    android:background="@android:color/holo_blue_dark">

    <TextView
        android:id="@+id/itemTo"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_margin="10dp"
        android:background="@android:color/holo_blue_bright"
        android:text="to"/>

</LinearLayout>


<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="90dp"
    android:layout_alignParentBottom="true"
    android:background="@android:color/holo_blue_dark">

    <TextView
        android:layout_width="90dp"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:background="@android:color/holo_blue_bright" />

    <TextView
        android:id="@+id/itemFrom"
        android:layout_width="90dp"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:text="from"
        android:background="@android:color/holo_blue_bright" />

    <TextView
        android:layout_width="90dp"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:background="@android:color/holo_blue_bright" />
</LinearLayout>

<View
    android:id="@+id/shuttle"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:background="@android:color/holo_blue_bright"/>

Activity class:

public class MainActivity extends AppCompatActivity {
    public static final int ANIMATION_SPEED = 3000;
    private RelativeLayout rootView;
    private View fromView, toView, shuttleView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rootView = (RelativeLayout) findViewById(R.id.rootView);
        fromView = findViewById(R.id.itemFrom);
        toView = findViewById(R.id.itemTo);
        shuttleView = findViewById(R.id.shuttle);

        fromView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Rect fromRect = new Rect();
                Rect toRect = new Rect();
                fromView.getGlobalVisibleRect(fromRect);
                toView.getGlobalVisibleRect(toRect);

                AnimatorSet animatorSet = getViewToViewScalingAnimator(rootView, shuttleView, fromRect, toRect, ANIMATION_SPEED, 0);

                animatorSet.addListener(new Animator.AnimatorListener() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                        shuttleView.setVisibility(View.VISIBLE);
                        fromView.setVisibility(View.INVISIBLE);
                    }

                    @Override
                    public void onAnimationEnd(Animator animation) {
                        shuttleView.setVisibility(View.GONE);
                        fromView.setVisibility(View.VISIBLE);
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {

                    }

                    @Override
                    public void onAnimationRepeat(Animator animation) {

                    }
                });
                animatorSet.start();
            }
        });
    }


    public static AnimatorSet getViewToViewScalingAnimator(final RelativeLayout parentView,
                                                           final View viewToAnimate,
                                                           final Rect fromViewRect,
                                                           final Rect toViewRect,
                                                           final long duration,
                                                           final long startDelay) {
        // get all coordinates at once
        final Rect parentViewRect = new Rect(), viewToAnimateRect = new Rect();
        parentView.getGlobalVisibleRect(parentViewRect);
        viewToAnimate.getGlobalVisibleRect(viewToAnimateRect);

        viewToAnimate.setScaleX(1f);
        viewToAnimate.setScaleY(1f);

        // rescaling of the object on X-axis
        final ValueAnimator valueAnimatorWidth = ValueAnimator.ofInt(fromViewRect.width(), toViewRect.width());
        valueAnimatorWidth.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // Get animated width value update
                int newWidth = (int) valueAnimatorWidth.getAnimatedValue();

                // Get and update LayoutParams of the animated view
                RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) viewToAnimate.getLayoutParams();

                lp.width = newWidth;
                viewToAnimate.setLayoutParams(lp);
            }
        });

        // rescaling of the object on Y-axis
        final ValueAnimator valueAnimatorHeight = ValueAnimator.ofInt(fromViewRect.height(), toViewRect.height());
        valueAnimatorHeight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // Get animated width value update
                int newHeight = (int) valueAnimatorHeight.getAnimatedValue();

                // Get and update LayoutParams of the animated view
                RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) viewToAnimate.getLayoutParams();
                lp.height = newHeight;
                viewToAnimate.setLayoutParams(lp);
            }
        });

        // moving of the object on X-axis
        ObjectAnimator translateAnimatorX = ObjectAnimator.ofFloat(viewToAnimate, "X", fromViewRect.left - parentViewRect.left, toViewRect.left - parentViewRect.left);

        // moving of the object on Y-axis
        ObjectAnimator translateAnimatorY = ObjectAnimator.ofFloat(viewToAnimate, "Y", fromViewRect.top - parentViewRect.top, toViewRect.top - parentViewRect.top);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setInterpolator(new DecelerateInterpolator(1f));
        animatorSet.setDuration(duration); // can be decoupled for each animator separately
        animatorSet.setStartDelay(startDelay); // can be decoupled for each animator separately
        animatorSet.playTogether(valueAnimatorWidth, valueAnimatorHeight, translateAnimatorX, translateAnimatorY);

        return animatorSet;
    }
}

You can do a whole bunch of customizations in terms of what appears and disappears at different stages of animation in animatorSet listener. Hope it's helpful.



回答2:

If someone is looking for simpler solution, you can use transitions framework: https://developer.android.com/training/transitions/index.html

To animate translation from one parent view to another, there is special transition ChangeTransform: https://developer.android.com/reference/android/transition/ChangeTransform.html

And a small example:

animatedView = View.inflate(ActivityMain.this, R.layout.item, firstParent);
animatedView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
Transition move = new ChangeTransform()
                        .addTarget(animatedView)
                        .setDuration(2000));
TransitionManager.beginDelayedTransition(rootParent, move);
firstParent.removeView(animatedView);
animatedView.setPadding(2,2,2,2);
animatedView.setElevation(4);
secondParent.addView(animatedView, 0);