Android過場動畫基礎教程
Tween(補間)動畫基礎
在討論系統動畫之前,我們先複習一下Tween動畫,也就是俗稱的補間動畫的基礎。
補間動畫的型別和屬性
補間動畫有4種型別:
- Alpha: 淡入淡出,改變透明度
- Scale: 大小縮放
- Translate: 位移變化
- Rotate:旋轉
Translate動畫的屬性
- android:fromXDelta:X軸的起始座標
- android:toXDelta:X軸的結束座標
- android:fromYDelta:Y軸的起始座標
- android:toYDelta:Y軸的結束座標
- android:duration:動畫時長
例:
<translate
android:duration="320"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromXDelta="100%"
android:interpolator="@android:anim/decelerate_interpolator"
android:toXDelta="0" />
所以上面的動畫是從螢幕最右(100%)到最左(0)進行位置移動。
我們再看Android L的activity open enter動畫:
Alpha動畫的屬性
- android:fromAlpha:起始時的透明度,1為不透明,0為全透明。
- android:toAlpha:結束時的透明度
例:
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:fillEnabled="true"
android:fillBefore="false" android:fillAfter="true"
android:duration="200"/>
這個動畫是由200ms的從全透明變成不透明。
Scale動畫的屬性
- android:fromXScale:起始X座標
- android:toXScale:結束X座標
- android:fromYScale:起始Y座標
- android:toYScale:結束Y座標
- android:pivotX:X軸的軸座標,也就是說X軸以這個軸為對稱軸
- android:pivotY:Y軸的軸座標
<scale
android:duration="300"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="true"
android:fromXScale=".8"
android:fromYScale=".8"
android:interpolator="@android:anim/decelerate_interpolator"
android:pivotX="50%p"
android:pivotY="50%p"
android:toXScale="1.0"
android:toYScale="1.0" />
於是上面的動畫解釋成,從X軸0.8位置,Y軸0.8位置,以父控制元件的50%為對稱軸,向X軸1.0位置,Y軸1.0位置進行放大。
Interpolator
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抽象類http://developer.android.com/reference/android/view/animation/BaseInterpolator.html,實現了Interpolator介面。
- LinearInterpolator
最省事兒的了。函式{noformat}y=x{noformat}
public float getInterpolation(float input) {
return input;
}
- AccelerateInterpolator
構造時可以指定係數,當係數為1.0f時,效果為y=x^2的拋物線,非1.0f時,則為x的係數次方,可以為非整數。實現加速效果。
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
<?xml version="1.0" encoding="utf-8"?>
<accelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="2.5" />
- DecelerateInterpolator
1.0f時,產生倒過來的y=x^2拋物線。實現減速效果
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
<?xml version="1.0" encoding="utf-8"?>
<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="2.5" />
- AccelerateDecelerateInterpolator
以0.5為界,先快後慢。官方文件上沒有演算法介紹,於是我們自己看code.
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
- CycleInterpolator
- 迴圈的,好辦啊,找個週期性函式就是了,比如正弦函式。
public float getInterpolation(float input) {
return (float)(Math.sin(2 * mCycles * Math.PI * input));
}
- AnticipateInterpolator
高階效果開始了,張力出馬。這個是開始的時候向後,然後向前甩的效果。公式:a(t) = t t ((tension + 1) * t – tension)。
public float getInterpolation(float t) {
return t * t * ((mTension + 1) * t - mTension);
}
- OvershootInterpolator
向前甩一定值後再回到原來位置
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;
}
- AnticipateOvershootInterpolator
開始的時候向後然後向前甩一定值後返回最後的值
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);
}
- BounceInterpolator
動畫結束的時候彈起
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;
}
- PathInterpolator
一個新的基於貝塞爾曲線或路徑物件的插入器
用法示例:frameworks/base/core/res/res/interpolator/linear_out_slow_in.xml
<?xml version="1.0" encoding="UTF-8"?>
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="0"
android:controlX2="0.2"
android:controlY1="0"
android:controlY2="1" />
如何使用Interpolator
直接引用android:anim的值
例:
android:interpolator="@android:anim/decelerate_interpolator"
寫個xml來設引數
例:
<?xml version="1.0" encoding="utf-8"?>
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:cycles="7" />
Activity的4種過場動畫
Activity有4種過場動畫可以定義:
- activityOpenEnterAnimation:表示新的activity建立進入效果
- activityOpenExitAnimation:表示activity還沒有finish()下退出效果
- activityCloseEnterAnimation:表示上一個activity返回進入效果
- activityCloseExitAnimation:表示的是activity finish()之後退出效果
Android 4.4的4種過場動畫
Android 4.4的activityOpenEnterAnimation
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top" >
<alpha
android:duration="300"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="true"
android:fromAlpha="0.0"
android:interpolator="@interpolator/decelerate_cubic"
android:toAlpha="1.0" />
<scale
android:duration="300"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="true"
android:fromXScale=".8"
android:fromYScale=".8"
android:interpolator="@interpolator/decelerate_cubic"
android:pivotX="50%p"
android:pivotY="50%p"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
其中,decelerate_cubic是以1.5倍速的因子減速。
<decelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="1.5" />
Android 4.4的activityOpenExitAnimation
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000"
android:zAdjustment="normal" >
<alpha
android:duration="300"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="true"
android:fromAlpha="1.0"
android:interpolator="@interpolator/decelerate_quint"
android:toAlpha="0.0" />
</set>
Android 4.4上的open exit動畫只有300ms的透明度從全不透明變成全透明,採用quint,2.5的速度減速。
Android 4.4的activityCloseEnterAnimation
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:zAdjustment="normal" >
<alpha
android:duration="300"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromAlpha="1.0"
android:toAlpha="1.0" />
</set>
300ms啥也沒幹啊。。。
Android 4.4的activityCloseExitAnimation
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top" >
<alpha
android:duration="300"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromAlpha="1.0"
android:interpolator="@interpolator/decelerate_cubic"
android:toAlpha="0.0" />
<scale
android:duration="300"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@interpolator/decelerate_cubic"
android:pivotX="50%p"
android:pivotY="50%p"
android:toXScale=".8"
android:toYScale=".8" />
</set>
跟open enter的動畫剛好是相反的,從1.01.0縮小到0.80.8。
Android 5.1的4種過場動畫
Android 5.1的activityOpenEnterAnimation
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top" >
<alpha
android:duration="200"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="true"
android:fromAlpha="0.0"
android:interpolator="@interpolator/decelerate_quart"
android:toAlpha="1.0" />
<translate
android:duration="350"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromYDelta="8%"
android:interpolator="@interpolator/decelerate_quint"
android:toYDelta="0" />
</set>
Android 5.1的activityOpenExitAnimation
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000"
android:zAdjustment="normal" >
<alpha
android:duration="217"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="true"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="0.7" />
</set>
Android 5.1上的open exit動畫變成217ms的透明度從全不透明變成0.7
Android 5.1的activityCloseEnterAnimation
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:zAdjustment="normal" >
<alpha
android:duration="250"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromAlpha="0.7"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="1.0" />
</set>
跟activityOpenExitAnimation的區別在於,250ms從0.7變成全不透明。
Android 5.1的activityCloseExitAnimation
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top" >
<alpha
android:duration="150"
android:fillAfter="true"
android:fillBefore="false"
android:fillEnabled="true"
android:fromAlpha="1.0"
android:interpolator="@android:anim/linear_interpolator"
android:startOffset="100"
android:toAlpha="0.0" />
<translate
android:duration="250"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromYDelta="0%"
android:interpolator="@interpolator/accelerate_quart"
android:toYDelta="8%" />
</set>
跟open enter的動畫剛好是相反的,從0開始向下移8%。但是時長有變化,漸變變成線性的了,退出變成加速。
<?xml version="1.0" encoding="UTF-8"?>
<accelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="2.0" />
framework相關程式碼分析
跟視窗動畫相關的方法主要在frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java中。
我們先看下核心邏輯中的
boolean applyAnimationLocked(int transit, boolean isEntrance)
transit型別
型別
- TRANSIT_UNSET:初始值,尚未設定
- TRANSIT_NONE:沒有動畫
- TRANSIT_ACTIVITY_OPEN:在同一task中在最頂端開啟一個視窗
- TRANSIT_ACTIVITY_CLOSE:關閉當前活動視窗,恢復同一個task中的上一個視窗
- TRANSIT_TASK_OPEN:新建任務並建立視窗
- TRANSIT_TASK_CLOSE:關閉當前活動視窗,回到上一個任務
- TRANSIT_TASK_TO_FRONT:將任務移至最頂
- TRANSIT_TASK_TO_BACK:將當前任務移至最末
- TRANSIT_WALLPAPER_CLOSE:關閉到無牆紙的應用
- TRANSIT_WALLPAPER_OPEN:起動牆紙應用
- TRANSIT_WALLPAPER_INTRA_OPEN:都有牆紙開啟
- TRANSIT_WALLPAPER_INTRA_CLOSE:有牆紙關閉
- TRANSIT_TASK_OPEN_BEHIND:在新任務啟動但是在後臺,一閃而過
- TRANSIT_TASK_IN_PLACE:就在現場畫動畫
附原始碼:
/** 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;
動畫的簡要流程
app transition的處理
WindowManagerService.handleAppTransitionReadyLocked -> WindowManagerService.setTokenVisibilityLocked -> WindowManagerService.applyAnimationLocked
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mOpeningApps.get(i);
final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
appAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;
appAnimator.animation = null;
setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToShow = false;
...
applyAnimation: anim=android.view.animation.AnimationSet@432426b0 animAttr=0x4 transit=4102 isEntrance=true
showAllWindows引出
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=true
Callers
com.android.server.wm.WindowStateAnimator.applyEnterAnimationLocked:1592
com.android.server.wm.WindowStateAnimator.performShowLocked:1494
com.android.server.wm.AppWindowAnimator.showAllWindowsLocked:313
結束app transition
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mClosingApps.get(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
wtoken.mAppAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;
wtoken.mAppAnimator.animation = null;
setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToHide = false;
// Force the allDrawn flag, because we want to start
// this guy`s animations regardless of whether it`s
// gotten drawn.
wtoken.allDrawn = true;
wtoken.deferClearAllDrawn = false;
}
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=false
Callers
com.android.server.wm.WindowManagerService.relayoutWindow:3392
com.android.server.wm.Session.relayout:191
android.view.IWindowSession$Stub.onTransact:235
Activity過載動畫的方法
overridePendingTransition(R.anim.alpha_in_animation, R.anim.alpha_out_animation);
相關文章
- canvas動畫教程-2 基礎設施Canvas動畫
- Android 動畫基礎知識學習(下)Android動畫
- 《HTML5+JavaScript動畫基礎》——第2章 動畫的JavaScript基礎2.1動畫基礎HTMLJavaScript動畫
- Android 轉場動畫Android動畫
- Android基礎動畫之Tween Animation和Frame AnimationAndroid動畫
- Flutter——動畫基礎(補間動畫)Flutter動畫
- Vue中的基礎過渡動畫原理解析Vue動畫
- Android入門教程 | Fragment 基礎概念AndroidFragment
- 79、 android基礎教程整理 (轉載)Android
- Android基礎 淡入淡出、上下彈出動畫的Android動畫
- 【matplotlib基礎】--動畫動畫
- Android基礎夯實--重溫動畫(四)之屬性動畫 ValueAnimator詳解Android動畫
- Android Transition(Android過渡動畫)Android動畫
- Android轉場動畫一說Android動畫
- CSS3動畫基礎CSSS3動畫
- 安卓動畫基礎講解安卓動畫
- Android基礎夯實–重溫動畫(三)之初識Property AnimationAndroid動畫
- Android基礎夯實--重溫動畫(三)之初識Property AnimationAndroid動畫
- Android基礎 EventBus3 0實用教程AndroidS3
- Android過渡動畫學習Android動畫
- Android轉場動畫深度解析(1)Android動畫
- Android轉場動畫深度解析(2)Android動畫
- Android轉場動畫深度解析(3)Android動畫
- Expression Blend例項中文教程(7) - 動畫基礎快速入門AnimationExpress動畫
- iOS 動畫基礎總結篇iOS動畫
- 前端基礎-jQuery的動畫效果前端jQuery動畫
- HT for Web基礎動畫介紹Web動畫
- iOS動畫系列之四:基礎動畫之平移篇iOS動畫
- Android基礎動畫之alpha透明度/translate平移/rotate旋轉Android動畫
- 萬彩動畫大師教程 | 增加滑入等進場動畫效果動畫
- NMAP 基礎教程
- MotionLayout 基礎教程
- typora基礎教程
- tkinter 基礎教程
- jQuery基礎教程jQuery
- Git基礎教程Git
- Memcache基礎教程
- 《Android Tablet 3程式設計基礎教程》介紹Android程式設計