Я недавно сделал анимацию подобного типа с помощью аниматоров. В общем, взгляды не будут отображаться вне границ их родителей, представление будет сокращено его границами родителей. Поэтому фокус состоит в том, чтобы разместить новое представление (shuttleView) поверх представления начала (fromView), которое вы хотите оживить, выровнять и изменить масштаб трансляции шаттла в целевом представлении (toView).
Это решение поддерживает масштабирование и перевод, вот пример: https://dl.dropboxusercontent.com/u/87080012/device-2016-06-03-111557.mp4
Вот код:
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"/>
Класс активности:
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;
}
}
Вы можете сделать целую кучу настроек с точки зрения того, что появляется и исчезает на разных этапах анимации в прослушивателе animatorSet. Надеюсь, это полезно.
Я не уверен, но вы можете попробовать использовать сцены https://developer.android.com/training/transitions/index.html?hl=ru – HotIceCream