Android Transition 页面过度动画
前言
对于Activity的过度动画都很熟悉了,大多数都是直接使用下面的函数,指定退出的Activity和进入的Activity动画
overridePendingTransition(enterAnim, exitAnim);
这种动画很简单,旋转平移翻转等,这些操作,而且是这个界面的操作。下面介绍一种更加美观的Activity过度动画
Android在新的sdk中给我们提供了另外一种Activity的过度动画——ActivityOptions。并且提供了兼容包——ActivityOptionsCompat。
一、 简介
ActivityOptionsCompat是一个静态类,提供了5个方法,如下:
-
ActivityOptionsCompat.makeCustomAnimation(Context context, int enterResId, int exitResId)
-
ActivityOptionsCompat.makeScaleUpAnimation(View source,int startX, int startY, int startWidth, int startHeight)
-
ActivityOptionsCompat.makeThumbnailScaleUpAnimation(View source,Bitmap thumbnail, int startX, int startY)
-
ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)
-
ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity,Pair
二、函数的使用
这里对这些函数的使用进行讲解:
2.1、makeCustomAnimation
makeCustomAnimation和overridePendingTransition非常类似,在实现效果上和overridePendingTransition也是相同的。
在界面A启动界面B
Activity A ——> Activity B
Activity A 中的代码:
public void click(View view) {
ActivityOptionsCompat compat = ActivityOptionsCompat.makeCustomAnimation(this,
R.anim.translate_in, R.anim.translate_none);
ActivityCompat.startActivity(this,
new Intent(this, Activity2.class), compat.toBundle());
}
三个参数,第一个是指当前activity,第二个和第三个参数分别是进入动画和退出动画,
ActivityCompat.startActivity()最后一个参数我们使用compat.toBundle。
Activity B 中的代码:
@Override
public void onBackPressed() {
super.onBackPressed();
ActivityCompat.finishAfterTransition(this);
}
退出的时候调用ActivityCompat.finishAfterTransition(this)进行退出动画。
2.2、makeScaleUpAnimation 比例放大动画
效果就是不断的 ,放大一个view,进而进行activity的过度,
private void launch(View view) {
ActivityOptionsCompat compat = ActivityOptionsCompat.makeScaleUpAnimation(view,
view.getWidth() / 2, view.getHeight() / 2, 0, 0);
ActivityCompat.startActivity(this, new Intent(this, Activity2.class),
compat.toBundle());
}
第1个参数是scale哪个view的大小,
第2和3个参数是以view为基点,从哪开始动画,这里是该view的中心,
第4和5参数是新的activity,从多大开始放大,这里是从无到有的过程。
2.3、makeThumbnailScaleUpAnimation
该方法和上面的makeScaleUpAnimation非常相似,只不过,这里是通过放大一个图片,最后过度到一个新的activity,
第2个参数是指那个图片要放大,
3和4参数表示从哪开始动画。
接下来我们要进入两个稍微复杂点的动画,这两个的方法名相同,都是makeSceneTransitionAnimation。
2.4、makeSceneTransitionAnimation 单个view的过度动画
什么是scene? 就是场景动画,在这里就体现在两个activity中的某些view协同去完成过度动画,先来看一个效果吧
Activity A ——> Activity B
Activity A中的代码
private void launch(View view) {
ActivityOptionsCompat compat =
ActivityOptionsCompat.makeSceneTransitionAnimation(this,
view, getString(R.string.transition));
ActivityCompat.startActivity(this, new Intent(this,
Activity2.class), compat.toBundle());
}
第一个参数:当前的activity
第二个参数:对这个view进行动画,来多过度到Activity B
第三个参数:view上指定的动画名称
因为要协作动画的两个view在不同的activity中,为了让这两个view产生关联,在xml配置项android:transitionName用来指定协作的view
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:scaleType="fitXY"
android:src="@drawable/show"
android:transitionName="@string/image" />
</RelativeLayout>
看ImageView的android:transitionName属性,为”@string/image”
Activity B中的代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:scaleType="fitXY"
android:src="@drawable/show"
android:transitionName="@string/image" />
</RelativeLayout>
也有一个android:transitionName属性,为”@string/image”的view
在makeSceneTransitionAnimation 的第三个参数是getString(R.string.transition)。这样这两个view就可以进行过渡动画了
2.5、makeSceneTransitionAnimation 多个view的协作
既然能指定一个view来进行协作,那肯定也能指定多个view了,来看看效果,
Activity A ——> Activity B
Activity A中的代码
private void launch() {
Pair<View, String> imagePair = Pair.create(mImageView, getString(R.string.image));
Pair<View, String> textPair = Pair.create(mTextView, getString(R.string.name));
ActivityOptionsCompat compat = ActivityOptionsCompat
.makeSceneTransitionAnimation(this, imagePair, textPair);
ActivityCompat.startActivity(this, new Intent(this, Activity2.class),
compat.toBundle());
}
-
通过Pair.create静态方法创建了两个Pair对象,这里有两个泛型,分别指定为View和String类型,create方法接受两个参数,第一个是参与动画的View,第二个是该View上的transitionName,和前面单一协作的类似,
-
用makeSceneTransitionAnimation方法创建一个compat,第二个参数是Pair类型,并且可以传入多个Pair类型的参数
-
最后用ActivityCompat.startActivity启动新的activity。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text"
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:transitionName="@string/name"
android:text="LOADER!!" />
<ImageView
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_above="@id/text"
android:layout_centerHorizontal="true"
android:src="@drawable/show"
android:transitionName="@string/image" />
</RelativeLayout>
Activity B中的代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:src="@drawable/show"
android:scaleType="fitXY"
android:transitionName="@string/image" />
<TextView
android:id="@+id/text"
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/image"
android:transitionName="@string/name"
android:layout_centerHorizontal="true"
android:text="LOADER!!" />
</RelativeLayout>
点击item ,其中多个元素过度到新的Activity
想要点击列表中的item,以过度动画的形式打开新的Activity,不能在item的xml布局文件中指定android:transitionName属性
因为屏幕中显示出来的item都会声明这个属性,只有第一个item的android:transitionName生效,就会导致所以的item的过度动画的开始位置,都是在第一个。
Activity A(列表界面) ——> Activity B(详情界面)
需要为不同的item创建不同的过度动画名称,代码如下:
1、在adapter中为每一个item的共享元素创建动画名称
class ListViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(post: PostWithUser, picasso: Picasso) {
with(post) {
itemView.tvTitle.text = postTitle
itemView.tvBody.text = getFormattedPostBody()
itemView.tvAuthorName.text = userName
picasso.load(getAvatarPhoto()).into(itemView.ivAvatar)
//SharedItem transition
ViewCompat.setTransitionName(itemView.tvTitle, postTitle)
ViewCompat.setTransitionName(itemView.tvBody, postBody)
ViewCompat.setTransitionName(itemView.tvAuthorName, userName)
ViewCompat.setTransitionName(itemView.ivAvatar, getAvatarPhoto())
}
}
}
2、Activity A中的代码
val intent = Intent(context, DetailsActivity::class.java)
intent.putExtra(SELECTED_POST, post)
//Transitions
intent.putExtra(TITLE_TRANSITION_NAME, ViewCompat.getTransitionName(tvTitle))
intent.putExtra(BODY_TRANSITION_NAME, ViewCompat.getTransitionName(tvBody))
intent.putExtra(AUTHOR_TRANSITION_NAME, ViewCompat.getTransitionName(tvAuthorName))
intent.putExtra(AVATAR_TRANSITION_NAME, ViewCompat.getTransitionName(ivAvatar))
val p1 = Pair.create(tvTitle as View, ViewCompat.getTransitionName(tvTitle))
val p2 = Pair.create(tvBody as View, ViewCompat.getTransitionName(tvBody))
val p3 = Pair.create(tvAuthorName as View, ViewCompat.getTransitionName(tvAuthorName))
val p4 = Pair.create(ivAvatar as View, ViewCompat.getTransitionName(ivAvatar))
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(context as Activity,p1,p2,p3,p4)
context.startActivity(intent, options.toBundle())
3、Activity B 中的代码
可以在xml中,指定共享view的动画名称,也可以通过代码来指定,如下,该函数在onCreate中调用
private fun handleTransition(extras: Bundle?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tvTitle.transitionName = extras?.getString(TITLE_TRANSITION_NAME)
tvBody.transitionName = extras?.getString(BODY_TRANSITION_NAME)
tvAuthorName.transitionName = extras?.getString(AUTHOR_TRANSITION_NAME)
ivAvatar.transitionName = extras?.getString(AVATAR_TRANSITION_NAME)
}
}
该代码来自示例:https://github.com/karntrehan/Posts
参考:
这篇文章实现的效果挺不错的 项目需求讨论 — 用Transition做一个漂亮的登录界面
Android自定义Transition动画
你所不知道的Activity转场动画——ActivityOptions
Android Transition(Android过渡动画)
使用Circular Reveal为你的应用添加揭露动画效果
关注我的公众号,轻松了解和学习更多技术