Android Transition——基础篇

今天来说一说Transition,这个我们肯定不陌生,实现共享元素就会用到这个API。Activities之间精美的动画也全靠这个来实现。从Kitkat版本就出现了SenceTransition场景转换)的概念,那么今天我们先来说一说这两个概念的基本用法。


  • Scene
    定义了界面当前的状态信息,保存了布局中所有View的属性值
  • Transition
    当一个场景改变的时候,transition主要负责:捕获每个View在开始场景和结束场景时的状态(各种属性值);根据两个场景(开始和结束)之间的区别自动创建一个Animator。
  • TransitionManager
    这个类将SenceTransition关联了起来,大多数情况下的场景变化都会使用AutoTransition。只有当应用程序需要不同的转换行为时,才需要指定其他的Transition来满足特定的场景需求。

    • setTransition(Scene scene, Transition transition)
      设置需要的场景与过渡动画

    • setTransition(Scene fromScene, Scene toScene, Transition transition)
      设置起始场景和结束场景与过渡动画

    • go(Scene scene)
      切换到指定的场景

    • go(Scene scene, Transition transition)
      切换到指定的场景以及所使用的过渡动画,transition如果传了null,那么就没有了过渡动画。

    • beginDelayedTransition(ViewGroup sceneRoot, Transition transition)
      可以自定义场景过渡的方法,调用此方法时,TransitionManager会捕获sceneRoot中View的属性值,然后发出请求以在下一帧上进行转换。那时候,sceneRoot中的新值将被捕获,变化的过程将会以动画的形式展现出来。我们没有必要创建一个新的Scene,因为这个方法主要是用来展现当前场景到下一帧的过渡效果。

    • void endTransitions (ViewGroup sceneRoot)
      结束指定场景根目录在准备/正在进行的转换。

更详细的解释,请移步官方API。


AutoTransition

创建默认转场时使用的工具类,在场景更改期间实现自动淡化,移动视图并调整视图的大小的动画。例如:
我们为一个ViewGroup设置了背景,然后设置了一个Padding。

 TransitionManager.beginDelayedTransition(content, new AutoTransition());
 linearLayout.setPadding(100,100,100,100);

Android Transition——基础篇_第1张图片

ChangeBounds

这种转换捕捉了场景变化之前和之后的目标视图的布局范围,并在转换过程中为这些变化提供动画。例如:
和上面那个动画一样,我设置一个时间,这样看的更明显。

        ChangeBounds changeBounds=new ChangeBounds();
            changeBounds.setDuration(2000);
            TransitionManager.beginDelayedTransition(linearLayout,changeBounds);
            linearLayout.setPadding(100,100,100,100);

Android Transition——基础篇_第2张图片

ChangeClipBounds

ChangeClipBounds捕捉ViewgetClipBounds()场景变化之前和之后的变化,并在变换过程中为这些变化提供动画。例如:

        Rect rect = new Rect(50, 150, 200, 350);
            ChangeClipBounds changeClipBounds = new ChangeClipBounds();
            android.transition.TransitionManager.beginDelayedTransition(linearLayout, changeClipBounds);
            if (pos % 2 == 0) {
                ViewCompat.setClipBounds(imageView2,rect);
            }else{
                ViewCompat.setClipBounds(imageView2,null);
            }
            pos++;

Android Transition——基础篇_第3张图片

这个裁剪的坐标给的真是太合适了!

ChangeImageTransform

这个Transition在场景变化之前和之后会捕获一个ImageView的矩阵,并在转换的过程中生成动画。可以与ChangeBounds结合使用。例如:

if (v.getId() == R.id.button) {
            ChangeImageTransform changeImageTransform = new ChangeImageTransform();
            ChangeClipBounds changeClipBounds = new ChangeClipBounds();
            android.transition.TransitionManager.
                    beginDelayedTransition(content,
                            new TransitionSet().addTransition(changeImageTransform)
                                    .addTransition(changeClipBounds).setDuration(1000));
            switch (pos) {
                case 0:
                    Rect rect = new Rect(50, 150, 300, 450);
                    ViewCompat.setClipBounds(imageView2, rect);
                    imageView2.setScaleType(ImageView.ScaleType.CENTER);
                    break;
                case 1:
                    ViewCompat.setClipBounds(imageView2, null);
                    imageView2.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    break;
                case 2:
                    Rect rect1 = new Rect(100, 200, 300, 400);
                    ViewCompat.setClipBounds(imageView2, rect1);
                    imageView2.setScaleType(ImageView.ScaleType.FIT_XY);
                    break;
                case 3:
                    ViewCompat.setClipBounds(imageView2, null);
                    imageView2.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
                    break;
            }
            if (pos == 3) {
                pos = -1;

            }
            pos++;
        }

这里用到了TransitionSet(),后面会讲到的。

ChangeScroll(API23中添加)

转换场景时,捕捉目标View更改之前与更改之后滚动的属性,然后对滚动的属性添加了动画处理。(API级别太高了,以后试一下)

ChangeTransform

在过渡场景更改之前和之后捕捉视图的缩放和旋转,并在过渡期间添加动画。例如:

ChangeTransform changeTransform = new ChangeTransform();
            changeTransform.setDuration(500);
            android.transition.TransitionManager.beginDelayedTransition(content, changeTransform);
            imageView.setRotation(pos+90);

Android Transition——基础篇_第4张图片


Explode(爆炸?)

此转换会捕捉目标视图从开始到结束的可见性,并且视图会从场景边缘移动出入。这里的可见性指的是setVisibility(int)的状态以及当前视图是否在ViewGroup层次结构中(比如recyclerView的Item的消失与显示)。如果没有设置焦点中心的话,那么视图默认会从场景中心移出去(像爆炸一样?)例如:

默认的情况下:

 final Rect viewRect = new Rect();
            bt.getLocalVisibleRect(viewRect);
            Transition transition = new Explode();
            transition.setEpicenterCallback(new Transition.EpicenterCallback() {
                @Override
                public Rect onGetEpicenter(Transition transition) {
                    return null;
                }
            });
            transition.setDuration(500);
            TransitionManager.beginDelayedTransition(content, transition);
            if(pos%2==0){
                imageView2.setVisibility(View.GONE);
                imageView.setVisibility(View.GONE);
                imageView3.setVisibility(View.GONE);
                imageView4.setVisibility(View.GONE);
            }else{
                imageView2.setVisibility(View.VISIBLE);
                imageView.setVisibility(View.VISIBLE);
                imageView3.setVisibility(View.VISIBLE);
                imageView4.setVisibility(View.VISIBLE);
            }
            pos++;

Android Transition——基础篇_第5张图片

当然了我们也可以自定义焦点,由Transition epicenter提供 (通过setEpicenterCallback方法来设置),例如:

final Rect viewRect = new Rect();
            bt.getLocalVisibleRect(viewRect);
            Transition transition = new Explode();
            transition.setEpicenterCallback(new Transition.EpicenterCallback() {
                @Override
                public Rect onGetEpicenter(Transition transition) {
                    return viewRect;
                }
            });
            transition.setDuration(500);
            TransitionManager.beginDelayedTransition(content, transition);
            if(pos%2==0){
                imageView2.setVisibility(View.GONE);
                imageView.setVisibility(View.GONE);
            }else{
                imageView2.setVisibility(View.VISIBLE);
                imageView.setVisibility(View.VISIBLE);
            }
           pos++;

Android Transition——基础篇_第6张图片

这里关于onGetEpicenter方法,我也不清楚这个返回的Rect是按照怎样的计算方式设置焦点的。

Fade

目标视图淡入淡出的过渡效果,视图可见性由设置了setVisibility(int)的状态以及是否在当前视图层次结构中确定。指定IN( MODE_IN)或者OUT(MODE_OUT)分别对应淡入和淡出。也可以通过fade.setMode方法设置,若不指定默认为淡入淡出效果。例如:

Transition transition = new Fade();
            transition.setDuration(500);
            TransitionManager.beginDelayedTransition(content, transition);

Android Transition——基础篇_第7张图片

Slide

就像前面那两个一样,目标视图滑动的过渡效果,视图可见性由设置了setVisibility(int)的状态以及是否在当前视图层次结构中确定。它帮助View从一测滑向另一测。默认是BOTTOM,当然了也可以自己设置。例如:

Transition transition = new Slide(Gravity.RIGHT);
            transition.setDuration(500);
            TransitionManager.beginDelayedTransition(content, transition);

Android Transition——基础篇_第8张图片

PathMotion

这个类有两个具体实现类ArcMotion和PatternPathMotion,这个基类可以在视图转换的时候沿着指定的路径运动。

  • ArcMotion
 Transition transition = new ChangeBounds();
            transition.setDuration(600);
            transition.setPathMotion(new ArcMotion());
            TransitionManager.beginDelayedTransition(content, transition);
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
            if (pos % 2 == 0) {
                params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
                params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
            } else {
                int[] rules = params.getRules();
                for (int i = 0; i < rules.length; i++) {
                    params.removeRule(i);
                }
            }
            imageView.setLayoutParams(params);
            pos++;

Android Transition——基础篇_第9张图片

  • PatternPathMotion
    可以使用Path定义两个坐标点之间的运动模式。而且必须具有与起点不同的终点。下面这个例子我随便写了一个坐标点,然后用Path连接起来,我们来看效果:
final Path path = new Path();
            path.moveTo(0, 0);
            path.quadTo(300, 0, 400, 450); 
            PathMotion pathMotion = new PathMotion() {
                @Override
                public Path getPath(float startX, float startY, float endX, float endY) {
                    return path;
                }
            };
            ChangeBounds changeBounds = new ChangeBounds();
            changeBounds.setPathMotion(pathMotion);
            TransitionManager.beginDelayedTransition(content,changeBounds);
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
            params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
            imageView.setLayoutParams(params);

Android Transition——基础篇_第10张图片

TransitionSet

TransitionSets可以实现更复杂的转换效果。ORDERING_SEQUENTIAL是一个一个的来 ORDERING_TOGETHER同时开始

 public void onClick(View v) {
                mExpanded = !mExpanded;
                TransitionManager.beginDelayedTransition(transitionsContainer, new TransitionSet()
                    .addTransition(new ChangeBounds())
                    .addTransition(new ChangeImageTransform()));
                ViewGroup.LayoutParams params = imageView.getLayoutParams();
                params.height = mExpanded ? ViewGroup.LayoutParams.MATCH_PARENT : ViewGroup.LayoutParams.WRAP_CONTENT;
                imageView.setLayoutParams(params);
                imageView.setScaleType(mExpanded ? ImageView.ScaleType.CENTER_CROP : ImageView.ScaleType.FIT_CENTER);
            }

这个TransitionSet其实就像AnimationSet那样,把所有的转场效果集合在一起,然后按照规则来执行。

每次写博客,都不知道该怎么结尾。算了,吐槽一句:
食堂打饭的阿姨,总是给我一点点菜,搞得我吃不饱。

你可能感兴趣的:(Android)