Android 4.4.2 (API level 19)引入Transition框架,以后不少APP上都使用该框架作出很酷炫的效果,视频中介绍了该框架的基本使用以及其中核心的一些类和方法,只有学会这些基本的API才能在以后的Activity/Fragment过渡定制一些本身想要的效果。android
先看官网的一张关系图git
图中有三个核心的类,分别是Scene、Transition和TransitionManager,下面对这个三个核心类展开分析。github
Scene场景,用于保存布局中全部View的属性值,建立Scene的方式能够经过getSceneForLayout方法
getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context)
好比:算法
mScene0 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene0, getContext());
mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, getContext());复制代码
也能够直接new Scene(ViewGroup sceneRoot, View layout)api
View view0 = inflater.inflate(R.layout.scene0, container, false); View view1 = inflater.inflate(R.layout.scene1, container, false); mScene0 = new Scene(mSceneRoot, view0); mScene1 = new Scene(mSceneRoot, view1);复制代码
两种方式都须要传SceneRoot,即该场景的根节点。markdown
Transition过渡动画,前面建立了两个场景,分别保存了视图的一些属性,好比Visibility、position等,Transition就是对于这些属性值的改变定义过渡的效果。从上图能够看到系统内置了一些经常使用的Transition,Transition的建立能够经过加载xml,如:框架
res/transition/fade_transition.xmlide
<fade xmlns:android="http://schemas.android.com/apk/res/android" />复制代码
而后在代码中:工具
Transition mFadeTransition =
TransitionInflater.from(this).
inflateTransition(R.transition.fade_transition);复制代码
或者直接在代码中:oop
Transition mFadeTransition = new Fade();复制代码
TransitionManeger用于将Scene和Transition联系起来,它提供了一系列的方法如setTransition(Scene fromScene, Scene toScene, Transition transition)指明起始场景和结束场景、他们的过渡动画是什么,go(Scene scene, Transition transition),到指定的场景所使用的过渡动画是什么,beginDelayedTransition(ViewGroup sceneRoot, Transition transition),在当前场景到下一帧的过渡效果是什么。好比这里使用go()方法,效果:
注意这里两个Scene中红绿两个方块除了位置和大小不同,id是一致的,transition记录下两个Scene先后属性值,根据属性值的改变执行过渡动画,默认状况下对SceneRoot下的全部View执行动画效果,咱们能够经过Transition.addTarget和removeTarget方法选择性添加或移除执行动画的View。
有时候咱们只想改变当前已展现的视图层级中View的状态,能够经过beginDelayedTransition实现,下面列举系统内置的Transition的使用。
AutoTransition默认的动画效果,对应xml tag为autoTransition
实际上是如下几个动画组合顺序执行:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="sequential"> <fade android:fadingMode="fade_out" /> <changeBounds /> <fade android:fadingMode="fade_in" /> </transitionSet>复制代码
在代码中使用:
TransitionManager.beginDelayedTransition(mRoot, new AutoTransition()); if (mTextView.getVisibility() != View.VISIBLE) { mTextView.setVisibility(View.VISIBLE); } else { mTextView.setVisibility(View.GONE); }复制代码
ChangeBounds对应xml tag为changeBounds,根据先后布局界限的变化执行动画
TransitionManager.beginDelayedTransition(mRoot, new ChangeBounds()); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mTarget.getLayoutParams(); if ((lp.gravity & Gravity.START) == Gravity.START) { lp.gravity = Gravity.BOTTOM | Gravity.END; } else { lp.gravity = Gravity.TOP | Gravity.START; } mTarget.setLayoutParams(lp);复制代码
ChangeClipBounds对应xml tag为changeClipBounds,做用对象:View的getClipBounds()值
Rect BOUNDS = new Rect(20, 20, 100, 100); TransitionManager.beginDelayedTransition(mRoot, new ChangeClipBounds()); if (BOUNDS.equals(ViewCompat.getClipBounds(mImageView))) { ViewCompat.setClipBounds(mImageView, null); } else { ViewCompat.setClipBounds(mImageView, BOUNDS); }复制代码
对应xml tag为changeImageTransform,做用对象:ImageView的matrix
TransitionManager.beginDelayedTransition(mRoot, new ChangeImageTransform());
mImageView.setScaleType(ImageView.ScaleType.XXX);复制代码
对应xml tag为changeScroll,做用对象:View的scroll属性值
TransitionManager.beginDelayedTransition(mRoot, new ChangeScroll());
mTarget.scrollBy(-100, -100);复制代码
对应xml tag 为changeTransform,做用对象:View的scale和rotation
TransitionManager.beginDelayedTransition(mRoot, new ChangeTransform()); if (mContainer2.getChildCount() > 0) { mContainer2.removeAllViews(); showRedSquare(mContainer1); } else { mContainer1.removeAllViews(); showRedSquare(mContainer2); mContainer2.getChildAt(0).setRotation(45); } private void showRedSquare(FrameLayout container) { final View view = LayoutInflater.from(getContext()) .inflate(R.layout.red_square, container, false); container.addView(view); }复制代码
对应xml tag为explode,做用对象:View的Visibility
TransitionManager.beginDelayedTransition(mRoot, new Explode()); int vis = mViews.get(0).getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE; for (View view : mViews) { view.setVisibility(vis); }复制代码
对应xml tag为fade,做用对象:View的Visibility
能够在初始化是指定IN或者OUT分别对应淡入和淡出,若不指定默认为淡入淡出效果
TransitionManager.beginDelayedTransition(mRoot, new Fade()); int vis = mViews.get(0).getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE; for (View view : mViews) { view.setVisibility(vis); }复制代码
对应xml tag为slide,做用对象:View的Visibility
TransitionManager.beginDelayedTransition(mRoot, new Slide()); int vis = mViews.get(0).getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE; for (View view : mViews) { view.setVisibility(vis); }复制代码
对应xml tag为transitionSet
能够在代码中建立transitionSet如:
mTransition = new TransitionSet(); mTransition.addTransition(new ChangeImageTransform()); mTransition.addTransition(new ChangeTransform()); TransitionManager.beginDelayedTransition(mOuterFrame, mTransition); if (mInnerFrame.getChildCount() > 0) { mInnerFrame.removeAllViews(); addImageView(mOuterFrame, ImageView.ScaleType.CENTER_CROP, mPhotoSize); } else { mOuterFrame.removeViewAt(1); addImageView(mInnerFrame, ImageView.ScaleType.FIT_XY, FrameLayout.LayoutParams.MATCH_PARENT); }复制代码
也能够经过加载xml布局建立transitionSet:
xml布局长这样:
<?xml version="1.0" encoding="utf-8"?> <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" android:transitionOrdering="together"> <changeImageTransform/> <changeTransform/> </transitionSet>复制代码
经过transitionOrdering属性设置动画执行的顺序,together表示同时执行,sequential表示顺序执行,在代码中能够调用TransitionSet的setOrdering(int)方法,属性值传ORDERING_SEQUENTIAL或者ORDERING_TOGETHER
在代码中:
mTransition = (TransitionSet) TransitionInflater.from(getContext()).inflateTransition(R.transition.transition); TransitionManager.beginDelayedTransition(mOuterFrame, mTransition); if (mInnerFrame.getChildCount() > 0) { mInnerFrame.removeAllViews(); addImageView(mOuterFrame, ImageView.ScaleType.CENTER_CROP, mPhotoSize); } else { mOuterFrame.removeViewAt(1); addImageView(mInnerFrame, ImageView.ScaleType.FIT_XY, FrameLayout.LayoutParams.MATCH_PARENT); }复制代码
这里结合changeImageTransform和changeTransform,效果以下:
Transition的辅助工具,以path的方式指定过渡效果,两个具体实现类ArcMotion和PatternPathMotion,看下ArcMotion的效果
mTransition = new AutoTransition(); mTransition.setPathMotion(new ArcMotion()); TransitionManager.beginDelayedTransition(mRoot, mTransition); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mTarget.getLayoutParams(); if ((lp.gravity & Gravity.START) == Gravity.START) { lp.gravity = Gravity.END | Gravity.BOTTOM; } else { lp.gravity = Gravity.START | Gravity.TOP; } mTarget.setLayoutParams(lp);复制代码
它的运动轨迹是条曲线,有兴趣的能够研究下它的实现算法,在源码中有个很萌的图以下:
除了系统内置的Transition,咱们还能够自定义Transition效果,须要继承Transition
public class CustomTransition extends Transition {
@Override
public void captureStartValues(TransitionValues values) {}
@Override
public void captureEndValues(TransitionValues values) {}
@Override
public Animator createAnimator(ViewGroup sceneRoot,
TransitionValues startValues,
TransitionValues endValues) {}
}复制代码
其工做原理是在captureStartValues和captureEndValues中分别记录View的属性值,官网建议确保属性值不冲突,属性值的命名格式参考:
package_name:transition_name:property_name复制代码
在createAnimator中建立动画,对比属性值的改变执行动画效果,如自定义修改颜色动画效果:
在两个Scene中使用自定义过渡动画,效果以下:
1.Android 版本在4.0(API Level 14)到4.4.2(API Level 19)使用Android Support Library's
2.对于 SurfaceView可能不起效果,由于SurfaceView的实例是在非UI线程更新的,所以会形成和其余视图动画不一样步。
3.某些特定的转换类型在应用到TextureView时可能不会产生所需的动画效果。
4.继承自AdapterView的如ListView,与该框架不兼容。
5.不要对包含文本的视图的大小进行动画