本文共 9488 字,大约阅读时间需要 31 分钟。
在讨论系统动画之前,我们先复习一下Tween动画,也就是俗称的补间动画的基础。
补间动画有4种类型:
例:
所以上面的动画是从屏幕最右(100%)到最左(0)进行位置移动。
我们再看Android L的activity open enter动画:
例:
这个动画是由200ms的从全透明变成不透明。
于是上面的动画解释成,从X轴0.8位置,Y轴0.8位置,以父控件的50%为对称轴,向X轴1.0位置,Y轴1.0位置进行放大。
Interpolator的用途在于控制插值显示的速度,可以支持加速减速的效果。
从API11开始,所有的Interpolator都是从TimeInterpolator接口派生出来的。TimeInterpolator只定义了一个方法:
public abstract float getInterpolation (float input)
输入值是[0.0,1.0]
区间的一个数,表示动画的进度。0.0表示动画开始,1.0表示动画结束。返回值是输入值的函数,值域也在[0.0,1.0]
中。
Interpolator接口实现了TimeInterpolator接口,但是并没有添加新的方法。Interpolator接口在API1时候就已经有了,只是继承关系不同。
从API 22开始,增加了BaseInterpolator抽象类,实现了Interpolator接口。
public float getInterpolation(float input) { return input;}
public float getInterpolation(float input) { if (mFactor == 1.0f) { return input * input; } else { return (float)Math.pow(input, mDoubleFactor); } }
例,改变阶数,按y=x^2.5曲线,来自frameworks/base/core/res/res/interpolator/accelerate_quint.xml
public float getInterpolation(float input) { float result; if (mFactor == 1.0f) { result = (float)(1.0f - (1.0f - input) * (1.0f - input)); } else { result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor)); } return result; }
例:frameworks/base/core/res/res/interpolator/decelerate_quint.xml
以0.5为界,先快后慢。官方文档上没有算法介绍,于是我们自己看code.
public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;}
public float getInterpolation(float input) { return (float)(Math.sin(2 * mCycles * Math.PI * input));}
高级效果开始了,张力出马。这个是开始的时候向后,然后向前甩的效果。公式:a(t) = t t ((tension + 1) * t - tension)。
public float getInterpolation(float t) { return t * t * ((mTension + 1) * t - mTension);}
向前甩一定值后再回到原来位置
public float getInterpolation(float t) { // _o(t) = t * t * ((tension + 1) * t + tension) // o(t) = _o(t - 1) + 1 t -= 1.0f; return t * t * ((mTension + 1) * t + mTension) + 1.0f;}
开始的时候向后然后向前甩一定值后返回最后的值
public float getInterpolation(float t) { // a(t, s) = t * t * ((s + 1) * t - s) // o(t, s) = t * t * ((s + 1) * t + s) // f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5 // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0 if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension); else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);}
动画结束的时候弹起
private static float bounce(float t) { return t * t * 8.0f; } public float getInterpolation(float t) { // _b(t) = t * t * 8 // bs(t) = _b(t) for t < 0.3535 // bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408 // bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644 // bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0 // b(t) = bs(t * 1.1226) t *= 1.1226f; if (t < 0.3535f) return bounce(t); else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f; else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f; else return bounce(t - 1.0435f) + 0.95f; }
一个新的基于贝塞尔曲线或路径对象的插入器
用法示例:frameworks/base/core/res/res/interpolator/linear_out_slow_in.xml例:
android:interpolator="@android:anim/decelerate_interpolator"
例:
Activity有4种过场动画可以定义:
其中,decelerate_cubic是以1.5倍速的因子减速。
Android 4.4上的open exit动画只有300ms的透明度从全不透明变成全透明,采用quint,2.5的速度减速。
300ms啥也没干啊。。。
跟open enter的动画刚好是相反的,从1.01.0缩小到0.80.8。
Android 5.1上的open exit动画变成217ms的透明度从全不透明变成0.7
跟activityOpenExitAnimation的区别在于,250ms从0.7变成全不透明。
跟open enter的动画刚好是相反的,从0开始向下移8%。但是时长有变化,渐变变成线性的了,退出变成加速。
跟窗口动画相关的方法主要在frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java中。
我们先看下核心逻辑中的boolean applyAnimationLocked(int transit, boolean isEntrance)
附源码:
/** Not set up for a transition. */ public static final int TRANSIT_UNSET = -1; /** No animation for transition. */ public static final int TRANSIT_NONE = 0; /** A window in a new activity is being opened on top of an existing one in the same task. */ public static final int TRANSIT_ACTIVITY_OPEN = 6; /** The window in the top-most activity is being closed to reveal the * previous activity in the same task. */ public static final int TRANSIT_ACTIVITY_CLOSE = 7; /** A window in a new task is being opened on top of an existing one * in another activity's task. */ public static final int TRANSIT_TASK_OPEN = 8; /** A window in the top-most activity is being closed to reveal the * previous activity in a different task. */ public static final int TRANSIT_TASK_CLOSE = 9; /** A window in an existing task is being displayed on top of an existing one * in another activity's task. */ public static final int TRANSIT_TASK_TO_FRONT = 10; /** A window in an existing task is being put below all other tasks. */ public static final int TRANSIT_TASK_TO_BACK = 11; /** A window in a new activity that doesn't have a wallpaper is being opened on top of one that * does, effectively closing the wallpaper. */ public static final int TRANSIT_WALLPAPER_CLOSE = 12; /** A window in a new activity that does have a wallpaper is being opened on one that didn't, * effectively opening the wallpaper. */ public static final int TRANSIT_WALLPAPER_OPEN = 13; /** A window in a new activity is being opened on top of an existing one, and both are on top * of the wallpaper. */ public static final int TRANSIT_WALLPAPER_INTRA_OPEN = 14; /** The window in the top-most activity is being closed to reveal the previous activity, and * both are on top of the wallpaper. */ public static final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15; /** A window in a new task is being opened behind an existing one in another activity's task. * The new window will show briefly and then be gone. */ public static final int TRANSIT_TASK_OPEN_BEHIND = 16; /** A window in a task is being animated in-place. */ public static final int TRANSIT_TASK_IN_PLACE = 17;
WindowManagerService.handleAppTransitionReadyLocked -> WindowManagerService.setTokenVisibilityLocked -> WindowManagerService.applyAnimationLocked
for (i=0; i
applyAnimation: anim=android.view.animation.AnimationSet@432426b0 animAttr=0x4 transit=4102 isEntrance=true
01-01 12:03:40.911 V/WindowStateAnimator( 747): [xulun]applyAnimation: win=WindowStateAnimator{4315ff60 com.yunos.alicontacts/com.yunos.alicontacts.activities.ContactEditorActivity} anim=0 attr=0x0 a=null transit=1 isEntrance=trueCallerscom.android.server.wm.WindowStateAnimator.applyEnterAnimationLocked:1592com.android.server.wm.WindowStateAnimator.performShowLocked:1494com.android.server.wm.AppWindowAnimator.showAllWindowsLocked:313
for (i=0; i
01-01 12:03:40.915 V/AppTransition( 747): applyAnimation: anim=android.view.animation.AnimationSet@431b2648 animAttr=0x5 transit=4102 isEntrance=false
01-01 12:03:41.058 V/WindowStateAnimator( 747): [xulun]applyAnimation: win=WindowStateAnimator{4323e988 com.yunos.alicontacts/com.yunos.alicontacts.CallDetailActivity} anim=0 attr=0x1 a=null transit=2 isEntrance=falseCallerscom.android.server.wm.WindowManagerService.relayoutWindow:3392com.android.server.wm.Session.relayout:191android.view.IWindowSession$Stub.onTransact:235
overridePendingTransition(R.anim.alpha_in_animation, R.anim.alpha_out_animation);
转载地址:http://bdbbm.baihongyu.com/