Android Transition 页面过度动画

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/xx326664162/article/details/81288389

前言

对于Activity的过度动画都很熟悉了,大多数都是直接使用下面的函数,指定退出的Activity和进入的Activity动画

overridePendingTransition(enterAnim, exitAnim);

这种动画很简单,旋转平移翻转等,这些操作,而且是这个界面的操作。下面介绍一种更加美观的Activity过度动画

Android在新的sdk中给我们提供了另外一种Activity的过度动画——ActivityOptions。并且提供了兼容包——ActivityOptionsCompat。

一、 简介

ActivityOptionsCompat是一个静态类,提供了5个方法,如下:

  1. ActivityOptionsCompat.makeCustomAnimation(Context context, int enterResId, int exitResId)

  2. ActivityOptionsCompat.makeScaleUpAnimation(View source,int startX, int startY, int startWidth, int startHeight)

  3. ActivityOptionsCompat.makeThumbnailScaleUpAnimation(View source,Bitmap thumbnail, int startX, int startY)

  4. ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)

  5. 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());
}
  1. 通过Pair.create静态方法创建了两个Pair对象,这里有两个泛型,分别指定为View和String类型,create方法接受两个参数,第一个是参与动画的View,第二个是该View上的transitionName,和前面单一协作的类似,

  2. 用makeSceneTransitionAnimation方法创建一个compat,第二个参数是Pair类型,并且可以传入多个Pair类型的参数

  3. 最后用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为你的应用添加揭露动画效果

关注我的公众号,轻松了解和学习更多技术
这里写图片描述

猜你喜欢

转载自blog.csdn.net/xx326664162/article/details/81288389