简述:transitions framework

下面翻译transition为“过渡”,强调动画过程的含义,不过更多时候使用transition单词本身。

Android 4.4.2 (API level 19) 引入了过渡框架,它用来在两个view hierarchies(就是ViewGroup实例)切换时执行改变动画。它通过动态修改views对象的某些property值来实现动画,实际上就是用的属性动画。框架内建了一些transition效果,也可以自定义。并且可以监听transition执行过程/生命周期(Lifecycle callbacks)各种回调。

框架概览

在UI改变时——view hierarchy(视图层级) 发生变化,过渡框架对包含的部分改变了的view对象执行属性动画

来表达这样的视觉提示(visual cues)。

特性

过渡框架包括下面这些特性:

  • 动画组Group-level animations

    视图层级发生变化时,可以同时执行多个动画,它们形成动画组,类似AnimationSet

  • Transition-based animation

    Runs animations based on the changes between starting and ending view property values.

  • Built-in animations

    Includes predefined animations for common effects such as fade out or movement.

  • Resource file support 支持资源文件方式的使用

    Loads view hierarchies and built-in animations from layout resource files.

  • Lifecycle callbacks

    Defines callbacks that provide finer control over the animation and hierarchy change process.

框架结构

下图是过渡框架涉及的相关概念和之间的关系:

  • Scene

    一个Scene表示一个view hierarchy,存储对应的views及其property值。

    一个Scene必须关联到一个scene-root,它是一个ViewGroup,正是对应view hierarchy要添加到的容器。

    Scene可以从layout文件创建(只能是整个布局文件对应的view hierarchy),或者代码生成的View/ViewGroup。

    如果仅指定目标Scene,那么框架使用当前scene-root对应的view hierarchy就作为开始的Scene。

  • Transition

    表示两个Scene之间的过渡动画,它保存了使用到的animations。

    TransitionManager用来执行专场效果。

    TransitionListener用来实现对过渡过程的监听。

存在的限制

SurfaceView非UI线程不保证同步;

AdapterView管理childView行为冲突;

TextView改变尺寸时显示问题;

TextureView非预期效果;

创建Scene

过渡涉及startScene和endScene,它们使用同一个sceneRoot,也就是变化的view hierarchy是在一个ViewGroup下的。

startScene可以不指定,那么就默认是当前view hierarchy。

如果连续执行多个Scene之前的切换,那么上一个endScene就是当前的startScene。

可以通过代码或layout文件创建Scene。

  • 代码文件,生成需要的ViewGroup对象即可,适合“动态创建”界面这样的需求。
Scene mScene;

// Obtain the scene root element
mSceneRoot = (ViewGroup) mSomeLayoutElement; // Obtain the view hierarchy to add as a child of
// the scene root when this scene is entered
mViewHierarchy = (ViewGroup) someOtherLayoutElement; // Create a scene
mScene = new Scene(mSceneRoot, mViewHierarchy);
  • layout文件
/**
* Returns a Scene described by the resource file associated with the given
* <code>layoutId</code> parameter. If such a Scene has already been created for
* the given <code>sceneRoot</code>, that same Scene will be returned.
* This caching of layoutId-based scenes enables sharing of common scenes
* between those created in code and those referenced by {@link TransitionManager}
* XML resource files.
*
* @param sceneRoot The root of the hierarchy in which scene changes
* and transitions will take place.
* @param layoutId The id of a standard layout resource file.
* @param context The context used in the process of inflating
* the layout resource.
* @return The scene for the given root and layout id
*/
public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context);

NOTE:

The framework creates the scene from the entire view hierarchy in the file; you can not create a scene from part of a layout file.

Create Scene Actions

使用Scene.setExitAction() or Scene.setEnterAction() ,传递定义的Runnable实例。

可以执行一些操作,比如修改ListView等。

Note:

Do not use scene actions to pass data between views in the starting and ending scenes. For more information, see Defining Transition Lifecycle Callbacks.

应用Transition

创建好startScene、endScene后,在改变UI的逻辑的地方,就可以执行Transition来开启专场动画了。

创建Transition

  • 资源文件

    在res/transition/目录下,创建表示Transition的文件,资源文件的方式更加复用而且简单。

    这种方式和定义动画文件的机制类似。

如res/transition/fade_transition.xml:

<fade xmlns:android="http://schemas.android.com/apk/res/android" />

然后加载它:

Transition mFadeTransition =
TransitionInflater.from(this).
inflateTransition(R.transition.fade_transition);
  • 代码方式

    例如:
Transition mFadeTransition = new Fade();

预提供的类型有ChangeBounds, ChangeClipBounds, ChangeImageTransform, ChangeTransform, TransitionSet, Visibility详见API文档。

开启过渡

使用下面的方法TransitionManager.go()

/**
* Convenience method to simply change to the given scene using
* the given transition.
*
* <p>Passing in <code>null</code> for the transition parameter will
* result in the scene changing without any transition running, and is
* equivalent to calling {@link Scene#exit()} on the scene root's
* current scene, followed by {@link Scene#enter()} on the scene
* specified by the <code>scene</code> parameter.</p>
*
* @param scene The Scene to change to
* @param transition The transition to use for this scene change. A
* value of null causes the scene change to happen with no transition.
*/
public static void go(Scene scene, Transition transition)

它有一个不含参数transition的重载,默认会使用AutoTransition

选择指定的目标view

默认情况下Transition的执行是针对Scene关联的view hierarchy中的所有views执行的。

可以通过Transition的方法removeTarget()、addTarget()来指定它影响的view。

比如若ListView不能通过框架正常完成过渡效果,那么移除它。

动画组:同时执行多个过渡效果

<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>

对应一个TransitionSet ,它是Transition的子类。

单Scene的过渡

如果UI在变化前后差距很小,例如就是同一个ViewGroup的简单的addView()/removeView()那么,此时可以不去执行像startScene、endScene那样的变化,使用delayed transition来在view hierarchy变化的时候开启过渡:

// Start recording changes to the view hierarchy
TransitionManager.beginDelayedTransition(mRootView, mFade); // Add the new TextView to the view hierarchy
mRootView.addView(mLabelText); // When the system redraws the screen to show this update,
// the framework will animate the addition as a fade in

Transition Lifecycle Callbacks

调用public Transition addListener (Transition.TransitionListener listener)

回调方法见Transition.TransitionListener

自定义Transition

A custom transition, like one of the built-in transition types, applies animations to child views of both the starting and ending scenes. Unlike built-in transition types, however, you have to provide the code that captures property values and generates animations. You may also want to define a subset of target views for your animation.

定义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()用来获取startScene、endScene关联的view的property值。可以对关心的view的属性值进行记录。

类似下面这样:

public class CustomTransition extends Transition {

    // Define a key for storing a property value in
// TransitionValues.values with the syntax
// package_name:transition_class:property_name to avoid collisions
private static final String PROPNAME_BACKGROUND =
"com.example.android.customtransition:CustomTransition:background"; @Override
public void captureStartValues(TransitionValues transitionValues) {
// Call the convenience method captureValues
captureValues(transitionValues);
} // For the view in transitionValues.view, get the values you
// want and put them in transitionValues.values
private void captureValues(TransitionValues transitionValues) {
// Get a reference to the view
View view = transitionValues.view;
// Store its background property in the values map
transitionValues.values.put(PROPNAME_BACKGROUND, view.getBackground());
}
...
}

TransitionValues是一个非常简单的数据结构,它保存和view关联的属性值,startScene和endScene分别使用一个TransitionValues对象来记录view hierarchy的各个view的状态。

要记录的“property_name”需要保存唯一,因为可能和其它Transition冲突,建议格式是:

package_name:transition_name:property_name

创建自定义Animator

过渡框架中的Transition使用属性动画作为动画机制的实现。

子自定义Transition重写createAnimator()方法来提供需要的动画逻辑,工作就是根据startValues和endValues来创建Animator。

针对有些view的过渡只在endScene或者startScene中有,所以startValues和endValues可能为null。

框架会为每一个动画的view创建一个Animator,也就是调用一次createAnimator()。

下面是一个案例ChangeColor.java:

public class ChangeColor extends Transition {

    /** Key to store a color value in TransitionValues object */
private static final String PROPNAME_BACKGROUND = "customtransition:change_color:background"; // BEGIN_INCLUDE (capture_values)
/**
* Convenience method: Add the background Drawable property value
* to the TransitionsValues.value Map for a target.
*/
private void captureValues(TransitionValues values) {
// Capture the property values of views for later use
values.values.put(PROPNAME_BACKGROUND, values.view.getBackground());
} @Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
} // Capture the value of the background drawable property for a target in the ending Scene.
@Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
// END_INCLUDE (capture_values) // BEGIN_INCLUDE (create_animator)
// Create an animation for each target that is in both the starting and ending Scene. For each
// pair of targets, if their background property value is a color (rather than a graphic),
// create a ValueAnimator based on an ArgbEvaluator that interpolates between the starting and
// ending color. Also create an update listener that sets the View background color for each
// animation frame
@Override
public Animator createAnimator(ViewGroup sceneRoot,
TransitionValues startValues, TransitionValues endValues) {
// This transition can only be applied to views that are on both starting and ending scenes.
if (null == startValues || null == endValues) {
return null;
}
// Store a convenient reference to the target. Both the starting and ending layout have the
// same target.
final View view = endValues.view;
// Store the object containing the background property for both the starting and ending
// layouts.
Drawable startBackground = (Drawable) startValues.values.get(PROPNAME_BACKGROUND);
Drawable endBackground = (Drawable) endValues.values.get(PROPNAME_BACKGROUND);
// This transition changes background colors for a target. It doesn't animate any other
// background changes. If the property isn't a ColorDrawable, ignore the target.
if (startBackground instanceof ColorDrawable && endBackground instanceof ColorDrawable) {
ColorDrawable startColor = (ColorDrawable) startBackground;
ColorDrawable endColor = (ColorDrawable) endBackground;
// If the background color for the target in the starting and ending layouts is
// different, create an animation.
if (startColor.getColor() != endColor.getColor()) {
// Create a new Animator object to apply to the targets as the transitions framework
// changes from the starting to the ending layout. Use the class ValueAnimator,
// which provides a timing pulse to change property values provided to it. The
// animation runs on the UI thread. The Evaluator controls what type of
// interpolation is done. In this case, an ArgbEvaluator interpolates between two
// #argb values, which are specified as the 2nd and 3rd input arguments.
ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(),
startColor.getColor(), endColor.getColor());
// Add an update listener to the Animator object.
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Object value = animation.getAnimatedValue();
// Each time the ValueAnimator produces a new frame in the animation, change
// the background color of the target. Ensure that the value isn't null.
if (null != value) {
view.setBackgroundColor((Integer) value);
}
}
});
// Return the Animator object to the transitions framework. As the framework changes
// between the starting and ending layouts, it applies the animation you've created.
return animator;
}
}
// For non-ColorDrawable backgrounds, we just return null, and no animation will take place.
return null;
}
// END_INCLUDE (create_animator) }

自定义Transition的使用和内建的Fade、ChangeBounds等是完全相同的。

(本文使用Atom编写)

札记:翻译-使用Scene和Transition实现【场景切换】动画效果的更多相关文章

  1. IOS自定义场景切换动画。

    IOS中我们可以通过Storyborad以及segue来实现我们自己的场景切换动画,新建项目使用Single View Application模板并取名为MyCustomSegue. 使用storyb ...

  2. cocos2d-x开发记录:二,基本概念(导演,场景,层和精灵,场景切换,效果)

    四,Director Scene Layer和Sprite(导演,场景,层和精灵) 1.Scenes(场景) 一个场景 (用CCScene对象实现)相当于APP工作流的独立部分.一些人也喜欢叫做“屏幕 ...

  3. cocos2d-x场景切换动画

    void StartScene::beginGame() {     CCLog("beginGame");          //CCTransitionScene *trans ...

  4. cocos2dx常见场景切换动画(转)

    本文转载自:http://www.cnblogs.com/linux-ios/archive/2013/04/09/3010779.html bool HelloWorld::init() { /// ...

  5. cocos2dx常见32种场景切换动画

    bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !CCLayer::init( ...

  6. Android共享元素场景切换动画的实现

    安卓5.0系统引入了共享元素,能做出非常炫酷的场景切换效果,这让人非常兴奋同时非常蛋疼,因为低版本没法使用啊,所以今天就跟大家分享一下自己写的一个库,其实只有2个文件而已就可以兼容安卓5.0以下的版本 ...

  7. 纯CSS3制作卡通场景汽车动画效果

    前言 今天分享一下我昨晚做的CSS3动画效果——卡通场景汽车动画.在接触CSS3动画之前,我之前实现一些简单的动画效果都是使用flash完成的.但是自从CSS3横空出世,在移动端对CSS3动画的运用越 ...

  8. [web前端] css3 transition属性实现3d动画效果

    cp from : https://www.cnblogs.com/chrxc/p/5123375.html transition属性是一个很强大的3d动画属性,我动手试了一下,很多在网上很火的网页动 ...

  9. css3 transition属性实现3d动画效果

    transition属性是一个很强大的3d动画属性,我动手试了一下,很多在网上很火的网页动画都可以用这个属性实现,只能说这个属性是在是太强大啦,本人在学习次属性之后才知道自己对css3的认识还是偏少, ...

随机推荐

  1. tp5框架中jquery+ajax分页

    jaxa分页,点击按钮直接替换数据, //php代码$page=Request::instance()->param("page"); $page = empty($page ...

  2. css:pointer-events: none

    css3新属性pointer-events: none: pointer-events: none 顾名思义,就是鼠标事件拜拜的意思.元素应用了该 CSS 属性,链接啊,点击啊什么的都变成了 “浮云牌 ...

  3. laravel PHPExcel 使用小结

    最近需求要用到PHPExcel,laravel框架中有相应的组件https://github.com/Maatwebsite/Laravel-Excel,我用的是2.1的(3.0文档不详细而且坑似乎也 ...

  4. 关于如何安装使用Git、tortoiseGit、Git@osc

    摘要: 讲解git在git@osc上使用的正确入门姿势. 关于Git代码托管的好处,这里就不再进行说明了.相信想去使用的人都应该有所了解啦.在使用开源中国里面的git@osc时,我们得先做入下几个工作 ...

  5. Linux的nmon监控结果分析文件中网络分析NET

    1.首先,使用# ifconfig查看Linux系统中的网卡名称,有的是eth0,有的是em1,以查看结果为准,下图为em1 2.先试试Linux系统中有没有安装ethtool工具,没有的话,下载et ...

  6. (转)2018CRM系统最新排行榜

    https://www.jianshu.com/p/718cc29de91f 2018CRM系统最新排行榜 深谷幽兰呼 关注 2018.09.04 10:22 字数 1524 阅读 3182评论 0喜 ...

  7. SSM商城项目(四)

    1. 学习计划 1.图片服务器 2.图片服务器安装 3.图片服务器的使用 4.图片上传功能 5.富文本编辑器的使用方法 6.商品添加功能实现 2. 图片服务器 1.存储空间可扩展. 2.提供一个统一的 ...

  8. html2canvas

    最近公司有个需求,实现html 页面元素转为png图像,这边用了html2canvas来实现.,这里记录一下,避免以后忘了~~ 官网链接: http://html2canvas.hertzen.com ...

  9. centos下通过pid查看进程的绝对路径的方法

    例如: 我想要知道我执行中的mysql路径 netstat -nlp pid拿到15330,然后 cd /proc/15330 由于linux在启动一个进程时,会在/proc下创建一个以PID命名的文 ...

  10. POJ-3268.SilverCowParty.(最短路 + 图的转置)

    本题思路:对原图和原图的逆图分别用一次最短路,找出最大值即可. 一开始是我是对每个顶点spfa搜了一波,结果判题时间巨长,还好这个题的数据量不是很大,所以就用了另一种思路. 参考代码:spfa单结点爆 ...