美文网首页
Android动画之Transition和TransitionM

Android动画之Transition和TransitionM

作者: sliencexiu | 来源:发表于2019-08-06 07:47 被阅读0次

    1 Transition概述

    Transition 在前一篇已经简单讲解了它的使用Android动画之场景变换Transition动画的使用,这次接着讲解Transition的其他用法和TransitionManager。

    Transition内部使用了属性动画实现,所以它可以认为是属性动画的封装。Transition两个核心概念为:场景(scenes)和变换(transitions),场景是UI当前状态,变换则定义了在不同场景之间动画变化的过程。所以Transition主要负责两个方面的事,一是保存开始和结束场景的两种状态,二是在两种状态之间创建动画。由于场景记录了内部所有View的开始和结束状态,所以Transition动画更具连贯性。谁执行动画呢?TransitionManager负责执行动画的任务。

    2 Scene 场景

    Scene 场景 场景过渡动画就是实现View从一种状态变化到另外一种状态,Scene就代表一个场景,它内部保存一个完整地视图结构,从根ViewGroup到所有子view,还有它们的所有状态信息。所以Scene最终就一个设置了不同属性特征的ViewGroup。

    Scene构造函数
    Scene(ViewGroup sceneRoot)
    sceneRoot:根ViewGroup,用于承载Scene view
    Scene(ViewGroup sceneRoot, View layout)
    参数说明:
    sceneRoot:根ViewGroup
    layout:view布局

    Scene一般利用getSceneForLayout()函数生成Scene场景
    Scene.getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context)
    参数说明
    sceneRoot:根ViewGroup,内部包含多个场景viewGroup。
    layoutId:view的布局文件资源id,代表一个场景。
    context:上下文
    代码示例:

    Activity layout

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".Main9Activity">
    
    <FrameLayout
        android:id="@+id/viewcontainer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </FrameLayout>
    
    </android.support.constraint.ConstraintLayout>
    

    scene1 layout

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
    android:id="@+id/imageview1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/image_home_game_nor"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="10dp"/>
    
        <ImageView
    android:id="@+id/imageview2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/image_home_game_nor2"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="10dp"
            app:layout_constraintRight_toRightOf="parent"/>
    
    </android.support.constraint.ConstraintLayout>
    

    scene2 layout 只是图片调换了位置

    生成Scene方法一:

    Scene scene1 = Scene.getSceneForLayout(mContainer, R.layout.scene1, Main9Activity.this);
    Scene scene2 = Scene.getSceneForLayout(mContainer, R.layout.scene2, Main9Activity.this);
    

    除了利用getSceneForLayout外,根据Scene的构造函数,我们还可以传入View直接构造Scene。
    生成Scene方法二:

    View view1 = LayoutInflater.from(Main9Activity.this).inflate(R.layout.scene1, null);
    View view2 = LayoutInflater.from(Main9Activity.this).inflate(R.layout.scene2, null);
    
    Scene scene1 = new Scene(mContainer, view1);
    Scene scene2 = new Scene(mContainer, view1);
    

    3 TransitionManager

    TransitionManager在场景变换时控制transitions的执行。通过TransitionManager可以添加场景和Transition变换,但为场景变化设置一个默认transitions是没有必要的,因为默认会使用AutoTransition。

    TransitionManager当场景变换时开启动画的方式:
    beginDelayedTransition(ViewGroup sceneRoot, Transition transition)
    beginDelayedTransition(ViewGroup sceneRoot)
    场景变幻时传入场景的view根sceneRoot,和transition动画。如果不指定Transition,默认为AutoTransition。

    go(Scene scene, Transition transition)
    go(Scene scene)
    go的方式需要传入scene,scene由Scene利用view生成。如果不指定Transition,则默认为AutoTransition。

    Transiton系统效果

    继承Transiton类的效果

    • ChangeBounds:检测view的位置边界创建移动和缩放动画
    • ChangeTransform:检测view的scale和rotation创建缩放和旋转动画
    • ChangeClipBounds:检测view的剪切区域的位置边界,和ChangeBounds类似。不过ChangeBounds针对的是view而ChangeClipBounds针对的是view的剪切区域(setClipBound(Rect rect) 中的rect)。如果没有设置则没有动画效果
    • ChangeImageTransform:检测ImageView的尺寸,位置以及ScaleType,并创建相应动画。
    • Fade,Slide,Explode:根据view的visibility的状态执行渐入渐出,滑动,分解动画。

    go 两个场景切换

    public class Main9Activity extends AppCompatActivity {
        private FrameLayout mContainer;
        boolean togger = true;
        Scene scene1 ;
        Scene scene2 ;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main9);
            mContainer = findViewById(R.id.viewcontainer);
            mContainer.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (togger){
                        TransitionManager.go(scene1,new ChangeBounds());
                    }else{
                        TransitionManager.go(scene2,new ChangeBounds());
                    }
                    togger = !togger;
                }
            });
            init();
        }
    
        private void init() {
             scene1 = Scene.getSceneForLayout(mContainer, R.layout.scene1, Main9Activity.this);
             scene2 = Scene.getSceneForLayout(mContainer, R.layout.scene2, Main9Activity.this);
       }
    
    

    如果不指定Transition为ChangeBounds。

    mContainer.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (togger){
               // TransitionManager.go(scene1,new ChangeBounds());
                TransitionManager.go(scene1);
            }else{
                TransitionManager.go(scene2);
            }
            togger = !togger;
        }
    });
    

    效果图虽然没有指定Transition但是也有动画效果,其实如果不指定Transition,系统默认的Transition为AutoTransition。

    AutoTransition关键源码:

    private void init() {
        setOrdering(ORDERING_SEQUENTIAL);
        addTransition(new Fade(Fade.OUT)).
                addTransition(new ChangeBounds()).
                addTransition(new Fade(Fade.IN));
    }
    

    AutoTransition是个组合变换。

    slide效果
    TransitionManager.go(scene1,new Slide());

    Explode效果
    TransitionManager.go(scene1,new Explode());

    上面的例子都是对于xml layout 文件做变换,下面我们对已存在sceneRoot中的view做动画

    Activity的layout:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".Main9Activity">
    
    <FrameLayout
        android:id="@+id/viewcontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
        <FrameLayout
        android:id="@+id/viewcontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
     <ImageView
                android:layout_gravity="center"
                android:id="@+id/imageview1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/image_home_game_nor"
                android:scaleType="matrix"
                android:layout_marginTop="10dp"/>
    
            <ImageView
                android:layout_gravity="center"
                android:id="@+id/imageview2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/image_home_game_nor2"
                android:scaleType="matrix"
                android:layout_marginTop="10dp"/>
    </FrameLayout>
          
    </FrameLayout>
    
    </android.support.constraint.ConstraintLayout>
    

    然后取imageview1生成Scene,

    imageView = mContainer.findViewById(R.id.imageview1);
    
    imageView = mContainer.findViewById(R.id.imageview1);
            imageView2 = mContainer.findViewById(R.id.imageview2);
            scene1 = new Scene(mContainer, imageView);
            scene2 = new Scene(mContainer, imageView2);
    
    Container.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (togger){
                 Transition transition = new Fade();
                        transition.setDuration(1000);
                        TransitionManager.go(scene1,transition);
            }else{
                Transition transition = new Fade();
                        transition.setDuration(1000);
                        TransitionManager.go(scene2,transition);
            }
            togger = !togger;
        }
    });
    
    

    运行出错:
    Process: com.ldx.canvasdrawdemo, PID: 18825
    java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

    注意:
    利用Scene构造函数生成Scene时,需要sceneRoot,sceneRoot在动画开始时,会将sceneRoot中的所有子View都remove掉,然后在sceneRoot中加载结束场景。通过代码new Scene(mSceneRoot, view)生成Scene,view必须是sceneRoot的直接子view,或者view是没有parentview的,不然在addview的时候会报错。

    修改如下:
    让图片作为sceneRoot的直接子view。

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".Main9Activity">
    
    <FrameLayout
        android:id="@+id/viewcontainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
            <ImageView
                android:layout_gravity="center"
                android:id="@+id/imageview1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/image_home_game_nor"
                android:scaleType="matrix"
                android:layout_marginTop="10dp"/>
    
            <ImageView
                android:layout_gravity="center"
                android:id="@+id/imageview2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/image_home_game_nor2"
                android:scaleType="matrix"
                android:layout_marginTop="10dp"/>
    
    </FrameLayout>
    
    </android.support.constraint.ConstraintLayout>
    
      mContainer.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                 
                    if (togger){
                      Transition transition = new Fade();
                        transition.setDuration(1000);
                        TransitionManager.go(scene1,transition);
    
                    }else{
                       Transition transition = new Fade();
                        transition.setDuration(1000);
                        TransitionManager.go(scene2,transition);
                    }
                    togger = !togger;
                }
            });
    

    只对布局中的某些view做动画

    scene1和scene2 xml文件类似,只列举scene1 layout 文件

    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:id="@+id/imageview1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/image_home_game_nor"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="10dp"/>
    
        <ImageView
            android:id="@+id/imageview2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/image_home_game_nor2"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginTop="10dp"
            app:layout_constraintLeft_toLeftOf="parent"
           />
    
    </android.support.constraint.ConstraintLayout>
    

    可以利用Transition的addTarget(),removeTarget(),只对某些view做动画,或者不对某些view做动画。
    如果调用了addTarget则只对调用了这个函数的View做动画,其他View直接完成最终状态,如果调用了removeTarget则是对没有调用这个函数的其他view做动画。如果同时调用了两个函数,则调用removeTarget会从调用了addTarget中的view查找,然后剔除。

    mContainer.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (togger){
                Transition transition = new ChangeBounds();
                transition.addTarget(R.id.imageview1);
                TransitionManager.go(scene1,transition);
            }else{
                Transition transition = new ChangeBounds();
                transition.addTarget(R.id.imageview1);
                TransitionManager.go(scene2,transition);
               }
            togger = !togger;
        }
    });
    

    只对其中一个ImageView做动画:


    可以看到效果图中,有一个ImageView没有动画效果。

    beginDelayedTransition(ViewGroup sceneRoot, Transition transition)

    TransitionManager.go函数需要生成对应的Scene,beginDelayedTransiton则不需要,只需要填入sceneRoot和Transition就可以实现Transition动画。

    这个函数里面没有Scene,那它何时执行动画呢,很简单当view的某些属性信息改变时,就会执行动画,上面介绍go函数时使用了ChangeTransform,ChangeBounds,ChangeClipBounds
    ,ChangeImageTransform,但感觉他们效果差不多,其实这些属性主要用于beginDelayedTransition这个函数,当对应的属性改变时,会自动触发Transition动画。

    执行TransitionManager.beginDelayedTransition后,系统会保存一个当前视图树状态的场景,修改view的属性信息,在下一次绘制时,系统会自动对比之前保存的视图树,然后执行一步动画
    重要提醒:如果想让beginDelayedTransition有效果,必须每次改变视图属性之后,重新调用beginDelayedTransition,或者改变之前调用beginDelayedTransition,这样才能够保存当前view的状态,否则存储的属性没有改变,不会有动画效果。

    ChangeBounds尺寸改变

    mContainer.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Transition transition = new ChangeBounds();
            transition.setDuration(1000);
            TransitionManager.beginDelayedTransition(mContainer,transition);
            if (togger){
                          FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) imageView.getLayoutParams();
                layoutParams1.height =100;
                layoutParams1.width =100;
                imageView.setLayoutParams(layoutParams1);
            }else{
                FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) imageView.getLayoutParams();
                layoutParams2.height = 700;
                layoutParams2.width = 700;
                imageView.setLayoutParams(layoutParams2);
           }
            togger = !togger;
        }
    });
    

    Transition 缩放效果。
    ChangeImageTransform

    <ImageView
        android:layout_gravity="center"
        android:id="@+id/imageview1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/image_home_game_nor"
        android:scaleType="matrix"
        android:layout_marginTop="10dp"/>
    

    ImageView的scaleType 设置为matrix

    mContainer.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Transition transition = new ChangeImageTransform();
            transition.setDuration(1000);
            TransitionManager.beginDelayedTransition(mContainer,transition);
            if (togger){
                imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
            }else{
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            }
            togger = !togger;
        }
    });
    

    效果图:

    利用matrix缩放旋转ImageView,然后设置Transition,没有发现动画效果,有点疑惑还在看。

    Animation动画概述和执行原理
    Android动画之补间动画TweenAnimation
    Android动画之逐帧动画FrameAnimation
    Android动画之插值器简介和系统默认插值器
    Android动画之插值器Interpolator自定义
    Android动画之视图动画的缺点和属性动画的引入
    Android动画之ValueAnimator用法和自定义估值器
    Android动画之ObjectAnimator实现补间动画和ObjectAnimator自定义属性
    Android动画之ObjectAnimator中ofXX函数全解析-自定义Property,TypeConverter,TypeEvaluator
    Android动画之AnimatorSet联合动画用法
    Android动画之LayoutTransition布局动画
    Android动画之共享元素动画
    Android动画之ViewPropertyAnimator(专用于view的属性动画)
    Android动画之Activity切换动画overridePendingTransition实现和Theme Xml方式实现
    Android动画之ActivityOptionsCompat概述
    Android动画之场景变换Transition动画的使用
    Android动画之Transition和TransitionManager使用
    Android动画之圆形揭露动画Circular Reveal
    Android 动画之 LayoutAnimation 动画
    Android动画之视图动画的缺点和属性动画的引入

    相关文章

      网友评论

          本文标题:Android动画之Transition和TransitionM

          本文链接:https://www.haomeiwen.com/subject/yrvkdctx.html