Android Transition动画

来源:互联网 发布:暴风影音mac无法播放字幕 编辑:程序博客网 时间:2024/05/18 00:43

动画在app中的重要性我不用多说了,在应用中使用一些符合系统设计规范的动画可以显著提升用户体验和自身逼格,我们也接触过很多种动画,帧动画和属性动画大家应该很熟悉了,用的也比较多,今天我们要说的是Transition动画,这个Api是在API 19(Android 4.4)中加入的。

为什么要引入Transition?

由于在Android引入了Metrial Desigon之后,动画的场面越来越大,比如以前我们制作一个动画可能涉及到的View就一个,或者就那么几个,如果我们一个动画中涉及到了当前Activity视图树中的各个View,那么情况就复杂了。比如我们要一次针对视图树中的10个View进行动画,这些View的效果都不同,可能有的是平移,有的是旋转,有的是淡入淡出,那么不管是使用之前哪种方式的动画,我们都需要为每个View定义一个开始状态和结束状态【关键帧,比如放缩,我们得设置fromXScale和toXScale 】,随着View个数的增加,这个情况会越来越复杂。Transition主要做的事情是:

  1. 捕获每一个 View 的起始和结束状态
  2. 根据这些数据来创建从一个场景到另一个场景间的过渡动画。

Transition 例子

考虑这样一个例子,当用户点击屏幕,让activity中的view逐渐消失。使用安卓的transition框架,我们只需几行代码就可完成,如下:

public class ExampleActivity extends Activity implements View.OnClickListener {    private ViewGroup mRootView;    private View mRedBox, mGreenBox, mBlueBox, mBlackBox;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mRootView = (ViewGroup) findViewById(R.id.layout_root_view);        mRootView.setOnClickListener(this);        mRedBox = findViewById(R.id.red_box);        mGreenBox = findViewById(R.id.green_box);        mBlueBox = findViewById(R.id.blue_box);        mBlackBox = findViewById(R.id.black_box);    }    @Override    public void onClick(View v) {        TransitionManager.beginDelayedTransition(mRootView, new Fade());        toggleVisibility(mRedBox, mGreenBox, mBlueBox, mBlackBox);    }    private static void toggleVisibility(View... views) {        for (View view : views) {            boolean isVisible = view.getVisibility() == View.VISIBLE;            view.setVisibility(isVisible ? View.INVISIBLE : View.VISIBLE);        }    }}

为了更好的理解幕后发生的事情,让我们来一步一步的分析,假设最开始每个view都是可见的:

  1. 当点击事件发生之后调用TransitionManager的beginDelayedTransition()方法,并且传递了mRootView和一个Fade对象最为参数。之后,framework会立即调用transition类的captureStartValues()方法为每个view保存其当前的可见状态(visibility)。

  2. 当beginDelayedTransition返回之后,在上面的代码中将每个view设置为不可见。

  3. 在接下来的显示中framework会调用transition类的captureEndValues()方法,记录每个view最新的可见状态。

  4. 接着,framework调用transition的createAnimator()方法。transition会分析每个view的开始和结束时的数据发现view在开始时是可见的,结束时是不可见的。Fade(transition的子类)会利用这些信息创建一个用于把view的alpha属性变为0的AnimatorSet,并且将此AnimatorSet对象返回。

注意: 读者可以在这里回想假如不使用transition框架,我们自己使用属性动画(Animator)来实现是不是复杂很多,其实transition框架的作用就是封装了属性动画的操作。

这个简单的例子强调了transition框架的两个主要优点。第一、Transitions抽象和封装了属性动画,Animator的概念对开发者来说是透明的,因此它极大的精简了代码量。开发者所做的所有事情只是改变一下view前后的状态数据,Transition就会自动的根据状态的区别去生成动画效果。第二、不同场景之间变换的动画效果可以简单的通过使用不同的Transition类来改变,本例中用的是Fade。

这里写图片描述

实现上图中的那两个不同的动画效果可以将Fade替换成Slide或者Explode即可。在接下来的文章中你将会发现,这些优点将使得我们只用少量代码就可以创建复杂的Activity 和Fragment切换动画。在接下来的小节中,将看到是如何使用Lollipop的Activity 和Fragment transition API来实现这种变换的。

5.0中的Activity和Fragment Transition

Android 5.0中Transition可以被用来实现Activity或者Fragment切换时的异常复杂的动画效果。虽然在以前的版本中,已经可以使用Activity的overridePendingTransition() 和 FragmentTransaction的setCustomAnimation()来实现Activity或者Fragment的动画切换,但是他们仅仅局限与将整个视图一起动画变换。新的Lollipop api更进了一步,让单独的view也可以在进入或者退出其布局容器中时发生动画效果,甚至还可以在不同的activity/Fragment中共享一个view。

在开始讲解之前我们先做一些约定,虽然下面的约定是针对activity的,但是在Fragment中也是一样的约定。

A和B分别是两个Activity,假设activity A 调用activity B。将A代表调用Activity ,B代表被调用Activity。

Activity transition API围绕退出(exit),进入(enter),返回(return)和再次进入(reenter)四种transition。按照上面对A和B的约定,我这样描述这一过程。

Activity A的退出变换(exit transition)决定了在A调用B的时候,A中的View是如何播放动画的。

Activity B的进入变换(enter transition)决定了在A调用B的时候,B中的View是如何播放动画的。

Activity B的返回变换(return transition)决定了在B返回A的时候,B中的View是如何播放动画的。

Activity A的再次进入变换(reenter transition)决定了在B返回A的时候,A中的View是如何播放动画的。

最后framework提供了两种Activity transition- 内容transition和共享元素的transition:

A content transition determines how an activity’s non-shared views—called transitioning views—enter or exit the activity scene.

A shared element transition determines how an activity’s shared elements (also called hero views) are animated between two activities.


上图中演示了Google Play Newsstand 应用的效果,虽然我们无法查看它的源码,但是我敢打赌它用了以下的transition:

activity A 中exit和reenter transition是为null的,因为A中的非共享view在退出和再次进入的时候没有动画效果。
activity B中的enter content transition使用了自定义的slide-in变换。该变换使B中list的元素从下到上过度。
activity B中return content transition是一组TransitionSet,同时播放了两个子元素的变换:上半部分和下半部分的slide变换。看起来就像整个界面被从从中间分割成了两半。
enter and return 共享元素变换是用了ChangeImageTransform。让两个activity中的ImageView无缝切换。

Activity Transition API介绍

用5.0的API创建一个基本的Activity transition是较为简单的。下面的总结是实现Activity transition的步骤。这篇文章主要是对Activity transition做简单的介绍,作为引入的篇章。在后续的文章中我们再介绍一些高级的用法。

  • 在调用与被调用的activity中,通过设定Window.FEATURE_ACTIVITY_TRANSITIONS 和 Window.FEATURE_CONTENT_TRANSITIONS 来启用transition api ,可以通过代码也可以通过设置主题来启用:

代码方式,在setContentView之前调用:

getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

主题xml:

<item name="android:windowContentTransitions">true</item>
  • 分别在调用与被调用的activity中设置exit 和enter transition。Material主题默认会将exit的transition设置成null而enter的transition设置成Fade .如果reenter 或者 return transition没有明确设置,则将用exit 和enter的transition替代。

  • 分别在调用与被调用的activity中设置exit 和enter 共享元素的transition。Material主题默认会将exit的共享元素transition设置成null而enter的共享元素transition设置成@android:transition/move.如果reenter 或者 return transition没有明确设置,则将用exit 和enter的共享元素transition替代。

    开始一个activity的content transaction需要调用startActivity(Context, Bundle)方法,将下面的bundle作为第二个参数:


ActivityOptions.makeSceneTransitionAnimation(activity, pairs).toBundle();

其中pairs参数是一个数组:Pair

Fragment Transition API介绍

如果你想在Fragment中使用transition,除了一小部分区别之外和activity大体一致:

  1. Content的exit, enter, reenter, 和return transition需要调用fragment的相应方法来设置,或者通过fragment的xml属性来设置。

  2. 共享元素的enter和return transition也n需要调用fragment的相应方法来设置,或者通过fragment的xml属性来设置。

  3. 虽然在activity中transition是被startActivity()和finishAfterTransition()触发的,但是Fragment的transition却是在其被FragmentTransaction执行下列动作的时候自动发生的。added, removed, attached, detached, shown, ,hidden。

  4. 在Fragment commit之前,共享元素需要通过调用addSharedElement(View, String) 方法来成为FragmentTransaction的一部分。

原文链接 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0113/2310.html

兼容4.4以前的开源项目地址