1. 梗概
!!! 拆分一个页面的不同元素view,实现不同的animation...但是元素是 非共享的 !!!
content transition决定了非共享view元素在activity和fragment切换期间是如何进入或者退出场景的。根据google最新的Material Design设计语言,content transition让我们毫不费力的去协调Activity/Fragment切换过程中view的进入和退出,让这个过程更流畅。在5.0之后content transition可以通过调用Window和Fragment的如下代码来设置:
setExitTransition() //当A start B时,使A中的View退出场景的transition
setEnterTransition() //当A start B时,使B中的View进入场景的transition
setReturnTransition() //当B 返回 A时,使B中的View退出场景的transition
setReenterTransition() //当B 返回 A时,使A中的View进入场景的transition
//也可以直接在xml设置,通常都这么做
<item name="android:windowEnterTransition"></item>
<item name="android:windowExitTransition"></item>
<item name="android:windowReenterTransition"></item>
<item name="android:windowReturnTransition"></item>
以下图为例,演示了google play Games app如何通过content transition实现activity之间的平滑切换。当第二个activity开始的时候,enter transition让用户的头像从底部边缘慢慢滑入。而在activity退出的时候,屏幕被分成两半,各自消失在上下边缘。
2. 那么怎么使用Content Transition呢?
2.1 xml实现
定义 界面指定元素的转场动画
三、定义 界面指定元素 或界面间共享元素 的转场动画基础在Manifest.xml为相应的Activity设置相对于的style
<style name="BaseAnimationAppTheme" parent="android:Theme.Material">
<!-- 1. 开启过渡效果-->
<item name="android:windowContentTransitions">true</item>
<!-- 2. 指定 界面元素 进入/退出的动画效果,可以不全部实现(当然可以在代码中设置,前文已提)-->
<item name="android:windowEnterTransition">@anim/search_enter</item>
<item name="android:windowExitTransition">...</item>
<item name="android:windowReenterTransition">...</item>
<item name="android:windowReturnTransition">...</item>
/**还可以设置是否同步执行还是顺序执行
*默认情况下,material主题的应用中enter/return的content transition
*会在exit/reenter的content transitions结束之前开始播放(只是稍微早于)
*/
<!--A退出的动画和B进入的动画同步进行,代码中setWindowAllowEnterTransitionOverlap()实现-->
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<!--B返回的动画和A重新进入的动画同步进行,代码中setWindowAllowReturnTransitionOverlap()实现-->
<item name="android:windowAllowReturnTransitionOverlap">true</item>
</style>
- 启动Activity
ActivityOptionsCompat optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(this);
ActivityCompat.startActivity(this, intent, optionsCompat.toBundle());
4.退出时调用finishAfterTransition()
注意
1、Material主题默认会将exit的transition设置成null,enter的transition设置成Fade 。
2、如果reenter 或者 return transition没有明确设置,则将用exit 和enter的共享元素transition替代
2.2 Java代码实现(不推荐)
1、activity的style中开启内容过渡效果,并设置相应的theme
<item name="android:windowContentTransitions">true</item>
<!--A退出的动画和B进入的动画同步进行-->
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<!--B返回的动画和A重新进入的动画同步进行-->
<item name="android:windowAllowReturnTransitionOverlap">true</item
2.启动activity B
ActivityOptionsCompat optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(this);
ActivityCompat.startActivity(this, intent, optionsCompat.toBundle());
3、在B中使用内容变换
Slide slide=new Slide(Gravity.BOTTOM);
slide.setDuration(500);
//内容变换,不包括底部导航栏和状态栏
slide.excludeTarget(android.R.id.navigationBarBackground, true);
slide.excludeTarget(android.R.id.statusBarBackground, true);
slide.excludeTarget(R.id.appBarLayout, true);
getWindow().setEnterTransition(slide);
getWindow().setReturnTransition(slide);
//也可以在xml文件设置transition,使用TransitionInflater得到Transition,如下:
Transition slide=TransitionInflater.from(this).inflateTransition(R.transition.slide_anim);
slide.setDuration(500);
slide.excludeTarget(R.id.appBarLayout, true);
getWindow().setEnterTransition(slide);
getWindow().setReturnTransition(slide);
4.return时调用finishAfterTransition() :非强制的
3. 深入分析
3.1 Activity A 调用startActivity()
1.framework遍历A的View树,确定当A的exit transition运行时哪些view会退出场景(即哪些view是transitioning view)。
2.A的exit transition捕获A中transitioning view的开始状态。
3.framework将A中所有的transitioning view设置为INVISIBLE。
4.A的exit transition捕获到A中transitioning view的结束状态。
5.A的exit transition比较每个transitioning view的开始和结束状态,然后根据前后状态的区别创建一个Animator。Animator开始运行,同时transitioning view退出场景。
3.2 Activity B启动
1.framework遍历B的View树,确定当B的enter transition运行时哪些view会进入场景,transitioning view会被初始化为INVISIBLE。
2.B的enter transition捕获B中transitioning view的开始状态。
3.framework将B中所有的transitioning view设置为VISIBLE。
4.B的enter transition捕获到B中transitioning view的结束状态。
5.B的enter transition比较每个transitioning view的开始和结束状态,然后根据前后状态的区别创建一个Animator。Animator开始运行,同时transitioning view进入场景。
通过在每个transitioning view中来回切换INVISIBLE 和VISIBLE,framework确保content transition得到创建animation(期望的animation)所需的状态信息。
3.3 监听动画的变化过程
//当然也可以监听 Return,Exit,Reenter时的动画
getWindow().getEnterTransition().addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
下面来看一个简单的实现,先看效果
//AndroidManifest.xml
<activity
android:name=".ContentTransitionElementsActivity"
android:label="ContentTransitionElements"
android:theme="@style/AppTheme.ContentTransition" />
//style.xml
<style name="AppTheme.ContentTransition">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowEnterTransition">@transition/enter_content_transition</item>
<item name="android:windowReturnTransition">@transition/return_content_transition</item>
</style>
enter_content_transition.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<targets >
<target android:excludeId="@android:id/statusBarBackground"/> <!--状态栏-->
<target android:excludeId="@android:id/navigationBarBackground"/> <!--导航栏-->
</targets>
<!-- <fade android:duration="500">
<targets>
<target android:targetId="@android:id/statusBarBackground"/>
</targets>
</fade>-->
<slide android:slideEdge="left" android:startDelay="500">
<targets >
<target android:targetId="@id/tv_show"/>
</targets>
</slide>
<slide android:startDelay="700">
<targets >
<target android:targetId="@id/iv_left"/>
</targets>
</slide>
<slide android:startDelay="900">
<targets >
<target android:targetId="@id/iv_right"/>
</targets>
</slide>
</transitionSet>
return_content_transition.xml
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="800">
<slide android:slideEdge="top">
<targets>
<target android:targetId="@id/relay_flag" />
<!--<target android:targetId="@id/fab"/>
<target android:targetId="@id/icon_gg"/>
<target android:targetId="@id/image_bg"/>-->
</targets>
</slide>
<slide android:slideEdge="bottom">
<targets>
<target android:targetId="@id/bottom_container" />
<target android:targetId="@id/tv_show"/>
<target android:targetId="@id/iv_left"/>
<target android:targetId="@id/iv_right"/>
</targets>
</slide>
<fade>
<targets >
<target android:targetId="@android:id/statusBarBackground"/>
</targets>
</fade>
</transitionSet>
public class ContentTransitionElementsActivity extends AppCompatActivity {
FloatingActionButton fab;
View image_bg;
ImageView icon_gg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_transition);
fab=findViewById(R.id.fab);
image_bg=findViewById(R.id.image_bg);
icon_gg=findViewById(R.id.icon_gg);
getWindow().getEnterTransition().addListener(new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
Animator circularReveal = ViewAnimationUtils.createCircularReveal(image_bg, image_bg.getWidth() / 2, image_bg.getHeight() / 2
, icon_gg.getWidth()/2, Math.max(image_bg.getWidth(), image_bg.getHeight()));
image_bg.setBackgroundColor(Color.BLACK);
circularReveal.setDuration(600);
circularReveal.start();
}
@Override
public void onTransitionEnd(Transition transition) {
fab.animate()
.scaleY(1)
.scaleX(1)
.start();
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
}
@Override
public void onBackPressed() {
finishAfterTransition();
super.onBackPressed();
}
}
由此可见 :动画效果都在XML中实现了,Activity只要加载先关布局即可
代码:animatedTransitionsLearn-master
Transition系列文章
一、初识Transition—实现两个场景的变换
二、番外篇 Transition之ViewOverlay
三、定义 界面指定元素 或界面间共享元素 的转场动画基础
四、Content Transition实现非共享元素转场
五、SharedElementTransition之Activity间的转场
六、SharedElementTransition之Fragment间的转场
七、番外篇- 自定义Visibility
八、5.0以下实现共享转场
本篇参考 :
深入理解Content Transition :建议去了解一下
animatedTransitionsLearn-master
Android转场动画