Android Transition——基础篇

  • Post author:
  • Post category:其他


今天来说一说

Transition

,这个我们肯定不陌生,实现共享元素就会用到这个API。Activities之间精美的动画也全靠这个来实现。从Kitkat版本就出现了

Sence



Transition



场景



转换

)的概念,那么今天我们先来说一说这两个概念的基本用法。


  • Scene

    定义了界面当前的状态信息,保存了布局中所有View的属性值
  • Transition

    当一个场景改变的时候,transition主要负责:捕获每个View在开始场景和结束场景时的状态(各种属性值);根据两个场景(开始和结束)之间的区别自动创建一个Animator。
  • TransitionManager

    这个类将

    Sence



    Transition

    关联了起来,大多数情况下的场景变化都会使用

    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);

这里写图片描述

ChangeBounds

这种转换捕捉了场景变化之前和之后的目标视图的布局范围,并在转换过程中为这些变化提供动画。例如:

和上面那个动画一样,我设置一个时间,这样看的更明显。

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

这里写图片描述

ChangeClipBounds


ChangeClipBounds

捕捉

View



getClipBounds()

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

        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++;

这里写图片描述

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

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);

这里写图片描述


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++;

这里写图片描述

当然了我们也可以自定义焦点,由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++;

这里写图片描述

这里关于

onGetEpicenter

方法,我也不清楚这个返回的

Rect

是按照怎样的计算方式设置焦点的。

Fade

目标视图淡入淡出的过渡效果,视图可见性由设置了setVisibility(int)的状态以及是否在当前视图层次结构中确定。指定

IN( MODE_IN)

或者

OUT(MODE_OUT)

分别对应淡入和淡出。也可以通过

fade.setMode

方法设置,若不指定默认为淡入淡出效果。例如:

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

这里写图片描述

Slide

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

BOTTOM

,当然了也可以自己设置。例如:

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

这里写图片描述

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++;

这里写图片描述

  • 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);

这里写图片描述

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

那样,把所有的转场效果集合在一起,然后按照规则来执行。

每次写博客,都不知道该怎么结尾。算了,吐槽一句:

食堂打饭的阿姨,总是给我一点点菜,搞得我吃不饱。



版权声明:本文为sinat_33585352原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。