Android--列表页跳转详情页,动画效果需求之共享元素场景切换动画的实现
Posted 彬彬杨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android--列表页跳转详情页,动画效果需求之共享元素场景切换动画的实现相关的知识,希望对你有一定的参考价值。
上周给了一个列表页,跳详情页的动画需求,由于ios端这个需求已经做完,我就直接仿照这他们实现的样子来做的,做的时候发现跟自己最开始设想的还不一样
刚好周末有时间,来做个总结
说几个不一样的点,先放图,在看下面的demo例子,更好理解一些:
1.列表页item 里面的布局是 ImagView ,但是右图详情页的图片却不是Imageview,而是一个Xbanner轮播图,切有滑动功能
(2)下图这种大图的情况
左图列表的item布局也是个xbanner 右图同样是xbanner
下面先来说下
简单版本的,思路,先上路
这个就是一个简单的共享动画的跳转
public class BinTransition
public static final String EASY_TRANSITION_OPTIONS = "easy_transition_options";
public static final long DEFAULT_TRANSITION_ANIM_DURATION = 1000;
/**
* 开始的时候
*/
public static void startActivity(Intent intent, BinTransitionOptions options)
options.update();
intent.putParcelableArrayListExtra(EASY_TRANSITION_OPTIONS, options.getAttrs());
Activity activity = options.getActivity();
activity.startActivity(intent);
activity.overridePendingTransition(0, 0);
/**
* 带结果返回的开始
*/
public static void startActivityForResult(Intent intent, int requestCode, BinTransitionOptions options)
options.update();
intent.putParcelableArrayListExtra(EASY_TRANSITION_OPTIONS, options.getAttrs());
Activity activity = options.getActivity();
activity.startActivityForResult(intent, requestCode);
activity.overridePendingTransition(0, 0);
/**
* 调用此方法开始输入转换动画
*
* @param activity The Activity entering
* @param duration The duration of enter transition animation
* @param interpolator The TimeInterpolator of enter transition animation
* @param listener Animator listener, normally you can do your initial after animation end
*/
public static void enter(Activity activity, long duration, TimeInterpolator interpolator, Animator.AnimatorListener listener)
Intent intent = activity.getIntent();
ArrayList<BinTransitionOptions.ViewAttrs> attrs =
intent.getParcelableArrayListExtra(EASY_TRANSITION_OPTIONS);
runEnterAnimation(activity, attrs, duration, interpolator, listener);
public static void enter(Activity activity, long duration, Animator.AnimatorListener listener)
enter(activity, duration, null, listener);
public static void enter(Activity activity, TimeInterpolator interpolator, Animator.AnimatorListener listener)
enter(activity, DEFAULT_TRANSITION_ANIM_DURATION, interpolator, listener);
public static void enter(Activity activity, Animator.AnimatorListener listener)
enter(activity, DEFAULT_TRANSITION_ANIM_DURATION, null, listener);
public static void enter(Activity activity)
enter(activity, DEFAULT_TRANSITION_ANIM_DURATION, null, null);
private static void runEnterAnimation(Activity activity,
ArrayList<BinTransitionOptions.ViewAttrs> attrs,
final long duration,
final TimeInterpolator interpolator,
final Animator.AnimatorListener listener)
if (null == attrs || attrs.size() == 0)
return;
for (final BinTransitionOptions.ViewAttrs attr : attrs)
final View view = activity.findViewById(attr.id);
if (null == view)
continue;
view.getViewTreeObserver()
.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
@Override
public boolean onPreDraw()
view.getViewTreeObserver().removeOnPreDrawListener(this);
int[] location = new int[2];
view.getLocationOnScreen(location);
view.setPivotX(0);
view.setPivotY(0);
view.setScaleX(attr.width / view.getWidth());
view.setScaleY(attr.height / view.getHeight());
view.setTranslationX(attr.startX - location[0]); // xDelta
view.setTranslationY(attr.startY - location[1]); // yDelta
view.animate()
.scaleX(1)
.scaleY(1)
.translationX(0)
.translationY(0)
.setDuration(duration)
.setInterpolator(interpolator)
.setListener(listener);
return true;
);
/**
* 退出活动,调用此方法以启动退出转换动画
*/
public static void exit(Activity activity, long duration, TimeInterpolator interpolator)
Intent intent = activity.getIntent();
ArrayList<BinTransitionOptions.ViewAttrs> attrs = intent.getParcelableArrayListExtra(EASY_TRANSITION_OPTIONS);
runExitAnimation(activity, attrs, duration, interpolator);
public static void exit(Activity activity, TimeInterpolator interpolator)
exit(activity, DEFAULT_TRANSITION_ANIM_DURATION, interpolator);
public static void exit(Activity activity, long duration)
exit(activity, duration, null);
private static void runExitAnimation(final Activity activity,
ArrayList<BinTransitionOptions.ViewAttrs> attrs,
long duration,
TimeInterpolator interpolator)
if (null == attrs || attrs.size() == 0)
return;
for (final BinTransitionOptions.ViewAttrs attr : attrs)
View view = activity.findViewById(attr.id);
int[] location = new int[2];
view.getLocationOnScreen(location);
view.setPivotX(0);
view.setPivotY(0);
view.animate()
.scaleX(attr.width / view.getWidth())
.scaleY(attr.height / view.getHeight())
.translationX(attr.startX - location[0])
.translationY(attr.startY - location[1])
.setInterpolator(interpolator)
.setDuration(duration);
activity.findViewById(attrs.get(0).id).postDelayed(new Runnable()
@Override
public void run()
activity.finish();
activity.overridePendingTransition(0, 0);
, duration);
/**
* 过度动画选项
*/
public class BinTransitionOptions
private Activity activity;
private View[] views;
private ArrayList<ViewAttrs> attrs;
public BinTransitionOptions(Activity activity, View[] views)
this.activity = activity;
this.views = views;
public static BinTransitionOptions makeTransitionOptions(Activity activity, View... views)
return new BinTransitionOptions(activity, views);
public void update()
if (null == views)
return;
attrs = new ArrayList<>();
for (View v : views)
int[] location = new int[2];
v.getLocationOnScreen(location);
attrs.add(new ViewAttrs(
v.getId(),
location[0],
location[1],
v.getWidth(),
v.getHeight()
));
public Activity getActivity()
return activity;
public ArrayList<ViewAttrs> getAttrs()
return attrs;
public static class ViewAttrs implements Parcelable
public int id;
public float startX;
public float startY;
public float width;
public float height;
public ViewAttrs(int id, float startX, float startY, float width, float height)
this.id = id;
this.startX = startX;
this.startY = startY;
this.width = width;
this.height = height;
// Parcelable
@Override
public int describeContents()
return 0;
@Override
public void writeToParcel(Parcel dest, int flags)
dest.writeInt(this.id);
dest.writeFloat(this.startX);
dest.writeFloat(this.startY);
dest.writeFloat(this.width);
dest.writeFloat(this.height);
protected ViewAttrs(Parcel in)
this.id = in.readInt();
this.startX = in.readFloat();
this.startY = in.readFloat();
this.width = in.readFloat();
this.height = in.readFloat();
public static final Parcelable.Creator<ViewAttrs> CREATOR = new Parcelable.Creator<ViewAttrs>()
@Override
public ViewAttrs createFromParcel(Parcel source)
return new ViewAttrs(source);
@Override
public ViewAttrs[] newArray(int size)
return new ViewAttrs[size];
;
关键的一个地方
在两个布局中的两个视图之间使用相同的ID。
A列表页的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
>
<ImageView
android:id="@+id/iv_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@mipmap/avatar_male"
/>
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@+id/iv_icon"
android:text="name"
android:textColor="#5b5b5b"
android:textSize="20sp"
/>
</RelativeLayout>
B详情页的其中一部分布局
<ImageView
android:id="@+id/iv_icon"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="100dp"
android:src="@mipmap/avatar_male"
/>
在A页面,进行转换选项,并使用EasyTransition#startActivity启动 去B页面
EasyTransitionOptions options =
EasyTransitionOptions.makeTransitionOptions(
ActivityA.this,
findViewById(R.id.iv_icon),
findViewById(R.id.tv_name)); // 根据你自己的需求可以带上多个id
Intent intent = new Intent(ActivityA.this, ActivityB.class);
EasyTransition.startActivity(intent, options);
在B页面中, 退出效果
// onCreate
EasyTransition.enter(ActivityB.this);
// onBackPressed
EasyTransition.exit(ActivityB.this);
继续接着最开始的需求说,因为一开始牵涉到id不一致的问题,所以在布局里面嵌了一层布局 id是想通的(蒙层),跳转的时候 先显示蒙层的图,等动画结束,在隐藏蒙层就好了,效果就出来了
以上是关于Android--列表页跳转详情页,动画效果需求之共享元素场景切换动画的实现的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中从一个详情页跳转到另一个详情页并返回列表页?