概述
Android 4.4.2 (API level 19)引入Transition框架,之后很多APP上都使用该框架做出很酷炫的效果,如 Google Play Newsstand app
还有github上很火的plaid
在app中适当得使用上Transition能带来较好的用户体验,视频中介绍了该框架的基本使用以及其中核心的一些类和方法,只有学会这些基本的API才能在之后的Activity/Fragment过渡定制一些自己想要的效果。
先看官网的一张关系图
图中有三个核心的类,分别是Scene、Transition和TransitionManager,下面对这个三个核心类展开分析。
Scene
Scene场景,用于保存布局中所有View的属性值,创建Scene的方式可以通过getSceneForLayout方法
getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context)
比如:
1
2
|
mScene0 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene0, getContext());
mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, getContext());
|
也可以直接new Scene(ViewGroup sceneRoot, View layout)
1
2
3
4
|
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,即该场景的根节点。
Transition
Transition过渡动画,前面创建了两个场景,分别保存了视图的一些属性,比如Visibility、position等,Transition就是对于这些属性值的改变定义过渡的效果。从上图可以看到系统内置了一些常用的Transition,Transition的创建可以通过加载xml,如:
res/transition/fade_transition.xml
1
|
<fade xmlns:android="http://schemas.android.com/apk/res/android" />
|
然后在代码中:
1
2
3
|
Transition mFadeTransition =
TransitionInflater.from(this).
inflateTransition(R.transition.fade_transition);
|
或者直接在代码中:
1
|
Transition mFadeTransition = new Fade();
|
TransitionManager
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。
常用API
有时候我们只想改变当前已展示的视图层级中View的状态,可以通过beginDelayedTransition实现,下面列举系统内置的Transition的使用。
AutoTransition
AutoTransition默认的动画效果,对应xml tag为autoTransition
其实是以下几个动画组合顺序执行:
1
2
3
4
5
6
|
<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>
|
在代码中使用:
1
2
3
4
5
6
|
TransitionManager.beginDelayedTransition(mRoot, new AutoTransition());
if (mTextView.getVisibility() != View.VISIBLE) {
mTextView.setVisibility(View.VISIBLE);
} else {
mTextView.setVisibility(View.GONE);
}
|
ChangeBounds
ChangeBounds对应xml tag为changeBounds
,根据前后布局界限的变化执行动画
1
2
3
4
5
6
7
8
|
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
ChangeClipBounds对应xml tag为changeClipBounds
,作用对象:View的getClipBounds()值
1
2
3
4
5
6
7
|
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);
}
|
ChangeImageTransform
对应xml tag为changeImageTransform
,作用对象:ImageView的matrix
1
2
|
TransitionManager.beginDelayedTransition(mRoot, new ChangeImageTransform());
mImageView.setScaleType(ImageView.ScaleType.XXX);
|
ChangeScroll
对应xml tag为changeScroll
,作用对象:View的scroll属性值
1
2
|
TransitionManager.beginDelayedTransition(mRoot, new ChangeScroll());
mTarget.scrollBy(-100, -100);
|
ChangeTransform
对应xml tag 为changeTransform,作用对象:View的scale和rotation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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);
}
|
Explode
对应xml tag为explode
,作用对象:View的Visibility
1
2
3
4
5
|
TransitionManager.beginDelayedTransition(mRoot, new Explode());
int vis = mViews.get(0).getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE;
for (View view : mViews) {
view.setVisibility(vis);
}
|
Fade
对应xml tag为fade
,作用对象:View的Visibility
可以在初始化时指定IN或者OUT分别对应淡入和淡出,也可以通过fade.setMode方法设置,若不指定默认为淡入淡出效果
1
2
3
4
5
|
TransitionManager.beginDelayedTransition(mRoot, new Fade());
int vis = mViews.get(0).getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE;
for (View view : mViews) {
view.setVisibility(vis);
}
|
Slide
对应xml tag为slide
,作用对象:View的Visibility
可以初始化时传入Gravity.XX,也可以通过slide.setSlideEdge方法设置,默认方向为Gravity.BOTTOM
1
2
3
4
5
|
TransitionManager.beginDelayedTransition(mRoot, new Slide());
int vis = mViews.get(0).getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE;
for (View view : mViews) {
view.setVisibility(vis);
}
|
TransitionSet
对应xml tag为transitionSet
可以在代码中创建transitionSet如:
1
2
3
4
5
6
7
8
9
10
11
12
|
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布局长这样:
1
2
3
4
5
6
|
<?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
在代码中:
1
2
3
4
5
6
7
8
9
10
|
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,效果如下:
PathMotion
Transition的辅助工具,以path的方式指定过渡效果,两个具体实现类ArcMotion和PatternPathMotion,看下ArcMotion的效果
1
2
3
4
5
6
7
8
9
10
|
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效果,需要继承Transition
1
2
3
4
5
6
7
8
9
10
11
12
|
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的属性值,官网建议确保属性值不冲突,属性值的命名格式参考:
1
|
package_name:transition_name:property_name
|
在createAnimator中创建动画,对比属性值的改变执行动画效果,如自定义修改颜色动画效果:
在两个Scene中使用自定义过渡动画,效果如下:
Note
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.不要对包含文本的视图的大小进行动画
Thanks to
Transition学习笔记的更多相关文章
-
css笔记 - transition学习笔记(二)
开始把7,8月份学的css整理一下 transition过渡 1. CSS transition transition过渡 :用于当元素 从一种样式变换为另一种样式 时为元素添加效果. 2. tran ...
-
Vue.js学习笔记(2)vue-router
vue中vue-router的使用:
-
Android动画学习笔记-Android Animation
Android动画学习笔记-Android Animation 3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中 ...
-
KTHREAD 线程调度 SDT TEB SEH shellcode中DLL模块机制动态获取 《寒江独钓》内核学习笔记(5)
目录 . 相关阅读材料 . <加密与解密3> . [经典文章翻译]A_Crash_Course_on_the_Depths_of_Win32_Structured_Exception_Ha ...
-
<;老友记>;学习笔记
这是六个人的故事,从不服输而又有强烈控制欲的monica,未经世事的千金大小姐rachel,正直又专情的ross,幽默风趣的chandle,古怪迷人的phoebe,花心天真的joey——六个好友之间的 ...
-
Matplotlib学习笔记(二)
原 Matplotlib学习笔记 参考:Python数据科学入门教程 Python3.6.1 jupyter notebook .caret, .dropup > .btn > .car ...
-
Matplotlib学习笔记(一)
原 matplotlib学习笔记 参考:Python数据科学入门教程 Python3.6.1 jupyter notebook .caret, .dropup > .btn > .ca ...
-
Spark 基本函数学习笔记一
Spark 基本函数学习笔记一¶ spark的函数主要分两类,Transformations和Actions. Transformations为一些数据转换类函数,actions为一些行动类函数: ...
-
学习笔记-AngularJs(九)
到目前为止,我们所做的学习案例都是没有加任何动画效果的,对于以往来说,我们经常会去使用一些动画插件或是css框架(如:animate.css)来点缀我们的网页,这样显得生动,高大上,那么接下来我们可以 ...
随机推荐
-
sharepoint 2010 页面刷新时滚动条位置保持不变 Controlling scrollbar position on postback
sharepoint 2010 页面刷新时滚动条位置保持不变 Controlling scrollbar position on postback在sharepoint 2010中,如果当前页面的篇幅 ...
-
《Linux内核分析》课程总结
朱宇轲 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 不知不觉,在网易 ...
-
css调用外部样式和css样式说明剧中显示
<title>边走边乔</title><link href="css/style.css" rel="stylesheet" ty ...
-
MM 不哭 (tyvj 1097)
题目大意: 一条数轴上有 n 个 MM 在哭,需要tcboy去安慰,tcboy 一开始站在第k个MM身边,每个MM 哭都会减掉tcboy的RP. 确定安慰MM的顺序使得RP扣得最少.求 min(Rp_ ...
-
分享功能使用的UIPopoverController在iOS9 过期,替换为popoverPresentationController
记录一下 以备以后用到的时候拿出来看看.以前使用的: 1 if (UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom ...
-
CentOS7 安装Bind
简要记录安装Bind的过程以及遇到的问题 一. 虚拟机准备 准备了2台虚拟机,都是装的CentOS7 64_1的IP地址为192.168.1.160,2的地址为161.161作为DNS服务器. 二.下 ...
-
访问Access日期字段
在使用sql访问Access日期字段,应在变量前后加#,例子: s:=Format(select xueshID,name,times,qukbz,skdate,banji from dianmjil ...
-
javax.mail
摘抄 example: public static void sendEmail(ConfBean cBean, String filename, String filepath) { try { P ...
-
利用OpenVPN实现局域网内多台机器共享上网
本文转载自 https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-14- ...
-
Django分页(一)
Django分页(一) 手动实现简单分页 HTML <!DOCTYPE html> <html lang="en"> <head> <me ...