Android动画<第八篇>:转场动画与共享元素

我在第七篇Android动画<第七篇>:Activity切换动画已经实现了Activity的切换动画,在文章的最后,我留了一个悬念,即使用ActivityOptions来实现Activity的过度动画。

当跳转Activity时,常常使用如下代码实现

                startActivity(intent);

这个代码是我们常见的了,但是跳转Activity还有另一个方法

public void startActivity(Intent intent, @Nullable Bundle options)

这个带有Bundle参数的方法可以实现Activity的过度动画,第二个参数可以传递

ActivityOptions.makeSceneTransitionAnimation(this).toBundle()

但是,这个方法从Android5.0之后才推出,当我们做跳转动作时需要判断版本号,如下:

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
            }else{
                startActivity(intent);
            }

仅仅使用ActivityOptions是看不到动画的,需要配合Transition才能看到动画效果。

Activity之间的切换(过渡),可以看成场景和场景之间的切换(过渡),在切换(过渡)过程中可以添加Transition实现变换操作。

makeSceneTransitionAnimation字面上的意思可以看出:

make:制作
Scene:场景
Transition:过渡、切换、变换
Animation:动画

连起来的意思是:制作场景过渡动画,我把场景和场景之间的过渡动画称之为转场动画

makeSceneTransitionAnimation的第二个参数是一个可变长度的数组,源码如下:

@SafeVarargs
public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
        Pair... sharedElements) {
    ActivityOptions opts = new ActivityOptions();
    makeSceneTransitionAnimation(activity, activity.getWindow(), opts,
            activity.mExitTransitionListener, sharedElements);
    return opts;
}

sharedElements参数称之为共享元素

转场动画共享元素是本章的重点。

(1)转场动画

首先,设置下主题:


windowContentTransitions默认为true,意思是:是否允许使用transitions 。(不过这个属性应该没有作用了,我设置成false,transitions 依然可以使用)
windowAllowEnterTransitionOverlap默认为true,true为创建场景时,前后两个场景动画同时执行。false为创建场景时,前后两个场景动画顺序执行。
windowAllowReturnTransitionOverlap默认为true,true为销毁场景时,前后两个场景动画同时执行。false为销毁场景时,前后两个场景动画顺序执行。

想要实现动画,还需要用到Transition对象,Transition的完整包名是android.transition.Transition,是Android SDK自带的接口。

Transition有三个间接子类,分别是:Explode动画Fade动画Slide动画

根据源码注释,Explode和Slide都是移入移出的意思,Fade是淡入淡出的意思。

那么,这三种动画该怎么去实现呢?需要结合ActivityOptionsmakeSceneTransitionAnimation方法。

N Slide动画 Explode动画 Fade动画
效果展示
Android动画<第八篇>:转场动画与共享元素_第1张图片
167.gif
Android动画<第八篇>:转场动画与共享元素_第2张图片
168.gif
Android动画<第八篇>:转场动画与共享元素_第3张图片
169.gif
详细说明 Slide动画从边缘开始移入移出动画,默认从下方开始显示,可以用代码控制的方向有:左、上、右、下 Explode动画从中间开始移入移出动画,它没有方向 Fade动画官方注释给出的解释是淡入淡出的意思




[Slide代码]

跳转到SceneTransitionActivity界面:

            Intent intent = new Intent(MainActivity.this, SceneTransitionActivity.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
            }else{
                startActivity(intent);
            }

SceneTransitionActivity中需要设置:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Slide slide = new Slide();
        slide.setDuration(1000);
        slide.setSlideEdge(Gravity.LEFT);
        //创建Activity时的动画
        getWindow().setEnterTransition(slide);
        //销毁Activity时的过渡动画
        getWindow().setReturnTransition(slide);
        //从前台切换到后台时的动画
        getWindow().setExitTransition(slide);
        //Activity从后台切换到前台的动画
        getWindow().setReenterTransition(slide);
    }

[Explode代码]

跳转到SceneTransitionActivity界面:

            Intent intent = new Intent(MainActivity.this, SceneTransitionActivity.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
            }else{
                startActivity(intent);
            }

SceneTransitionActivity中需要设置:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Explode explode = new Explode();
        explode.setDuration(1000);
        //创建Activity时的动画
        getWindow().setEnterTransition(explode);
        //销毁Activity时的过渡动画
        getWindow().setReturnTransition(explode);
        //从前台切换到后台时的动画
        getWindow().setExitTransition(explode);
        //Activity从后台切换到前台的动画
        getWindow().setReenterTransition(explode);
    }

[Fade代码]

跳转到SceneTransitionActivity界面:

            Intent intent = new Intent(MainActivity.this, SceneTransitionActivity.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
            }else{
                startActivity(intent);
            }

SceneTransitionActivity中需要设置:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Fade fade = new Fade();
        fade.setDuration(3000);
        //创建Activity时的动画
        getWindow().setEnterTransition(fade);
        //销毁Activity时的过渡动画
        getWindow().setReturnTransition(fade);
        //从前台切换到后台时的动画
        getWindow().setExitTransition(fade);
        //Activity从后台切换到前台的动画
        getWindow().setReenterTransition(fade);
    }

以上三种动画用Java代码炫酷的实现了Activity的转场动画,那么除了使用Java代码实现之外还可以使用style方式实现:

样式:


布局文件:

Android动画<第八篇>:转场动画与共享元素_第4张图片
图片.png

transition_explode.xml



transition_fade.xml



transition_slide.xml



(2)共享元素

共享元素转场动画是两个不同的概念,转场动画是使用Transition对象产生的场景开始到结束的过渡动画,而共享元素是场景开始(场景A)的View和场景结束(场景B)的View相互绑定。

那么该如何绑定两个场景的View呢?

为了防止Transition混淆演示图效果,我暂时将Transition去掉,仅仅使用共享元素完成动画。

从上面的讲解,我们知道了Activity之间的跳转其实就是场景的切换,场景的切换动画是由Transition来实现的,那么共享元素也能实现特殊的动画。

startActivity的第二个参数的ActivityOptions.makeSceneTransitionAnimation方法可以传递共享元素,代码如下:

场景A跳转代码,将场景A的一个view和一个transitionName传递到场景二

View transition_view = findViewById(R.id.image_a);
String transition_name = getString(R.string.transition_name_image);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, transition_view, transition_name).toBundle());

当然,如果有多个共享元素,可以使用Pair对象

ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, Pair.create(transition_view, transition_name),  Pair.create(transition_view, transition_name)).toBundle()


当切换到场景二时,其中的某View也必须标注transitionName



两者相互绑定的View必须具有相同的transitionName(名字随便命名)

image

这样,场景A和场景B之间的元素形成了共享,这就是共享元素

效果如下:

Android动画<第八篇>:转场动画与共享元素_第5张图片
171.gif

从效果图中,可以明显的看出,图形1和图形2之间的动画效果。

转场动画共享元素结合使用效果如下:

Android动画<第八篇>:转场动画与共享元素_第6张图片
172.gif

我想大家都能看出,转场动画的时间和共享元素过渡动画的时间不一样,那是因为我将转场动画的时间设置为了1秒,而共享元素过渡动画的时间是系统默认。

那么,怎么调整共享元素过渡动画的时间呢?

我们可以设置style来调整共享元素的时间,代码如下:


其中,主要看最下面四个,共享元素动画设置

transition_set.xml



    
    
    
    
    
    
    
    

至于四个共享元素动画的配置是什么意思,看完文章上面部分,我想都能猜到。transitionSet属性下的changeBoundschangeTransformchangeClipBoundschangeImageTransform都有注释,这里不详细描述了。

最终效果如下:

Android动画<第八篇>:转场动画与共享元素_第7张图片
173.gif

(3)Fragment之间实现过渡动画

上面介绍了Activity之间的过渡动画,Fragment之间的过渡动画其实也差不多。

当Fragment切换时,的Transition动画

        Slide slideTransition = new Slide(Gravity.LEFT);
        slideTransition.setDuration(1000);
        demo2Fragment.setEnterTransition(slideTransition);

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, demo2Fragment)
                .commit();

效果如下:

Android动画<第八篇>:转场动画与共享元素_第8张图片
174.gif

它的效果和Activity切换效果看起来差不多。那么共享元素 动画该怎么去实现呢?

代码如下:

从Fragment1切换到Fragment2

public void jumpToFragment2(View view){

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

        Slide slideTransition = new Slide(Gravity.LEFT);
        slideTransition.setDuration(1000);
        demo2Fragment.setEnterTransition(slideTransition);

        Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.transition_set);
        demo2Fragment.setSharedElementEnterTransition(transition);

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, demo2Fragment)
                .addSharedElement(view, getString(R.string.transition_name_image))
                .commit();
    }else{
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, demo2Fragment)
                .commit();
    }
}

从Fragment2切换到Fragment1

public void jumpToFragment1(View view){

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

        Slide slideTransition = new Slide(Gravity.RIGHT);
        slideTransition.setDuration(1000);
        demo1Fragment.setEnterTransition(slideTransition);

        Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.transition_set);
        demo1Fragment.setSharedElementEnterTransition(transition);

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, demo1Fragment)
                .addSharedElement(view, getString(R.string.transition_name_image))
                .commit();
    }else{
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, demo1Fragment)
                .commit();
    }
}

在fragment1中的某view中绑定共享元素名称:transitionName


在fragment2中的某view中绑定共享元素名称:transitionName


我们先删除如下代码:

    Slide slideTransition = new Slide(Gravity.LEFT);
    slideTransition.setDuration(1000);
    demo2Fragment.setEnterTransition(slideTransition);

也就是删除Transition动画相关代码,效果如下:

Android动画<第八篇>:转场动画与共享元素_第9张图片
175.gif

加上Transition动画之后的效果如下:

Android动画<第八篇>:转场动画与共享元素_第10张图片
176.gif

最后,别忘了以下这两个方法(上面有介绍)

        demo1Fragment.setAllowEnterTransitionOverlap(false);
        demo1Fragment.setAllowReturnTransitionOverlap(false);

(4)布局间的场景动画

[第一步] 创建场景

Scene scene1 = Scene.getSceneForLayout(ll_yuan, R.layout.scene1, getActivity());

[第二步] 创建Transition

                Fade fade = new Fade(Fade.OUT);
                fade.setDuration(3000);

[第三步] 执行切换场景动画(三种方式)

        TransitionManager.go(scene1, fade);
        //TransitionManager.go(scene1, TransitionInflater.from(getActivity()).inflateTransition(R.transition.transition_set));
        //TransitionManager.go(scene1);

效果如下:

Android动画<第八篇>:转场动画与共享元素_第11张图片
177.gif

除了多个场景之间的过渡动画之外,还可以使用更改某一个场景的属性触发属性变化的动画。

[第一步]

TransitionManager.beginDelayedTransition

[第二步] 修改view属性

代码如下:

按钮一:

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                ChangeBounds changeBounds = new ChangeBounds();
                changeBounds.setDuration(3000);
                TransitionManager.beginDelayedTransition(ll_yuan, changeBounds);
                ViewGroup.LayoutParams params = image_yuan.getLayoutParams();
                params.width = 600;
                image_yuan.setLayoutParams(params);
            }

按钮二:

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                ChangeBounds changeBounds = new ChangeBounds();
                changeBounds.setDuration(3000);
                TransitionManager.beginDelayedTransition(ll_yuan, changeBounds);
                ViewGroup.LayoutParams params = image_yuan.getLayoutParams();
                params.width = 100;
                image_yuan.setLayoutParams(params);
            }

效果如下:

Android动画<第八篇>:转场动画与共享元素_第12张图片
178.gif

转场动画共享元素动画暂时就那么多了,其实还有很多动画效果和动画的组合都没说到,本章只是讲解基础,在后期的文章中尽量给大家补全。

[本章完...]

你可能感兴趣的:(Android动画<第八篇>:转场动画与共享元素)