Search code examples
androidanimationtranslate

Animate a view from one Layout to other Layout


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.

How animation should work

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

Solution

  • 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.