Android 動畫基礎知識學習(下)
學習資料:Android開發藝術探索
和Animation的api
1.屬性動畫
屬性動畫可以對任意物件的屬性進行動畫不僅僅是View
,動畫預設時間間隔是300ms
,預設幀率是100ms/幀
。
作用:在一個時間間隔內完成對一個物件從屬性值到另一個屬性值的改變。
三個常用類:ValueAnimator,ObjectAnimator,AnimatorSet
Java程式碼
private void initView() {
Button bt = (Button) findViewById(R.id.bt_object_animation_activity);
ImageView iv = (ImageView) findViewById(R.id.iv_object_animation_activity);
//改變背景屬性
ValueAnimator colorAnim = ObjectAnimator.ofInt(iv, "backgroundColor", Color.parseColor("#FF4081"), Color.CYAN);
colorAnim.setRepeatCount(2);
colorAnim.setRepeatMode(ObjectAnimator.REVERSE);
colorAnim.setDuration(1000);
colorAnim.setEvaluator(new ArgbEvaluator());//估值器
//動畫集合
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(iv, "rotationX", 0, 360),//繞x軸旋轉360度
ObjectAnimator.ofFloat(iv, "rotation", 0, -90),//逆時針旋轉90度
ObjectAnimator.ofFloat(iv, "translationX", 0, 90),//右移
ObjectAnimator.ofFloat(iv, "scaleY", 1, 0.5f),//y軸縮放到一半
ObjectAnimator.ofFloat(iv, "alpha", 1, 0.25f, 1)//透明度變換
);
//延遲一秒開始
set.setStartDelay(1000);
bt.setOnClickListener((v) -> {
//改變屬性 位置 向下移動iv高的二分之一
ObjectAnimator.ofFloat(iv, "translationY", iv.getHeight() / 2).start();
//背景屬性改變開始
colorAnim.start();
//集合動畫
set.setDuration(3000).start();
});
}
軸點預設為View
的中心點。
常用的propertyName
:
-
rotationX
圍繞x軸旋轉 -
rotationY
圍繞y軸旋轉 -
rotation
圍繞軸點旋轉 -
translationX
在x軸方向上平移 -
translationY
在y軸方向上平移 -
scaleX
在x軸方向縮放 -
scaleY
在y軸方向縮放 -
alpha
透明度 -
width
寬度 -
height
高度
1.2 常用方法介紹
1.2.1 ObjectAnimator
類
ObjectAnimator.ofFloat(Object target, String propertyName, float... values)
Constructs and returns an ObjectAnimator that animates between float values.
返回一個根據方法內的具體的values
建立的ObjectAnimator
物件
-
Object target
,目標控制元件View
的物件 -
String propertyName
,屬性的名字 -
float... values
,根據具體需求需要的屬性值
ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)
Constructs and returns an ObjectAnimator that animates between the sets of values specified in PropertyValueHolder objects
返回一個由PropertyValueHolder
物件建立的ObjectAnimator
物件
public void byPropertyValuesHolder(ImageView iv) {
PropertyValuesHolder pvh_1 = PropertyValuesHolder.ofFloat("rotationX", 0, 360);
PropertyValuesHolder pvh_2 = PropertyValuesHolder.ofFloat("rotation", 0, -90);
PropertyValuesHolder pvh_3 = PropertyValuesHolder.ofFloat("alpha", 1, 0.25f, 1);
ObjectAnimator.ofPropertyValuesHolder(iv, pvh_1, pvh_2, pvh_3).setDuration(1000).start();
}
ofInt(Object target, String propertyName, int... values)
Constructs and returns an ObjectAnimator that animates between int values.
返回一個由int
值屬性建立的ObjectAnimator
物件
-
setTarget(Object target)
設定動畫目標View
1.2.2 ValueAnimator
類
ValueAnimator
的setEvaluator(new ArgbEvaluator())
設定估值器addUpdateListener(ValueAnimator.AnimatorUpdateListener listener)
Adds a listener to the set of listeners that are sent update events through the life of an animation.
新增一個監聽,可以用來在動畫過程中改變屬性
setRepeatCount(int num)
設定動畫的迴圈次數,預設為0,-1為無限迴圈setStartDelay(long startDelay)
設定動畫開始的延遲時間
cancel()
取消一個正在進行的動畫。取消前,動畫進行到哪個狀態,取消後,就保持在那個狀態。end()
結束動畫。呼叫結束方法後,View
會跳轉到結束狀態。如果動畫設定了迴圈次數setRepeatCount()
和重複模式setRepeatMode(ObjectAnimator.REVERSE)
,結束狀態就要根據具體設定分析。
1.2.3 AnimatorSet
類
playTogether(Animator... items)
Sets up this AnimatorSet to play all of the supplied animations at the same time.
同時播放所有的Animator
動畫物件。
playSequentially(Animator... items)
Sets up this AnimatorSet to play each of the supplied animations when the previous animation ends.
順序播放Animator
動畫物件
setInterpolator(TimeInterpolator interpolator)
Sets the TimeInterpolator for all current child animations of this AnimatorSet.
設定插值器
1.2.4 Animator
類
直接子類:AnimatorSet
和 ValueAnimator
間接子類:ObjectAnimator
和 TimeAnimator
Animator
類的方法子類都可以直接使用。
addListener(Animator.AnimatorListener listener)
Adds a listener to the set of listeners that are sent events through the life of an animation, such as start, repeat, and end.
為動畫新增一個監聽過程的介面。如果不想實現AnimatorListener
介面中的所有方法也可以繼承AnimatorListenerAdapter
。
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
toast("動畫開始");
}
@Override
public void onAnimationEnd(Animator animator) {
toast("動畫結束");
}
@Override
public void onAnimationCancel(Animator animator) {
toast("動畫取消");
}
@Override
public void onAnimationRepeat(Animator animator) {
toast("動畫重建");
}
});
實現了介面中全部的方法。
繼承AnimatorListenerAdapter
:
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
toast("動畫結束");
}
});
根據實際需求,實現不同的方法。
addPauseListener(Animator.AnimatorPauseListener listener)
Adds a pause listener to this animator
為動畫增加暫停監聽
2.插值器和估值器
TimeInterpolator
,時間插值器。用來根據時間流逝的百分比來計算出當前屬性的值變化的百分比。
常用插值器:
名稱 | 作用 |
---|---|
LinearInterpolator |
線性插值器。勻速動畫 |
AccelerateDecelerateInterpolator |
加速減速插值器 |
DecelerateInterpolator |
勻減速插值器。動作越來越慢 |
BounceInterpolator |
回彈插值器。到達平移後,回彈 |
CycleInterpolator |
迴圈插值器。在兩點間往還運動 |
PathInterpolator |
路徑插值器。根據單一方向定義的路徑座標運動 |
OvershootInterpolator |
超越插值器。超出後,再返回來 |
AnticipateInterpolator |
預期插值器。先反向運動再根據指定的方向運動 |
都是Interpolator
的子類
TypeEvaluator
,型別估值演算法(估值器)。用來根據當前屬性變化改變的百分比來計算改變後的屬性值。
-
IntEvaluator
,針對整型屬性 -
FloatEvaluator
,針對浮點型屬性 -
ArgbEvaluator
,針對Color
屬性
2.1簡單Demo
private void initView() {
Button bt = (Button) findViewById(R.id.bt_interpolator_activity);
ImageView iv = (ImageView) findViewById(R.id.iv_interpolator_activity);
LinearLayout root = (LinearLayout) findViewById(R.id.root_interpolator_activity);//根佈局
AnimatorSet set = new AnimatorSet();
set.setInterpolator(new BounceInterpolator());
set.setDuration(3000);
//利用View的post方法拿到根佈局的高度
root.post(() -> {
//計算下降高度
int height = root.getHeight() - iv.getHeight() - bt.getHeight();
//設定動畫
set.play(ObjectAnimator.ofFloat(iv, "translationY", height));
});
bt.setOnClickListener(v ->set.start());
}
利用BounceInterpolator
可以很方便的做出模擬小球下落的動畫。也可以根據需求進行自定義插值器。
2.2 對任意屬性做動畫
對Object
的屬性abc
做動畫,必須滿足2個條件:
-
object
必須提供setAbc()
的方法。如果動畫的時候沒有傳遞初始值,還要提供getAbc()
方法。因為系統要去abc
的初始值。如果不滿足,程式直接Crash
-
object
的setAbc
對屬性abc
所做的改變必須能夠通過某種方法反映出來,比如UI
改變之類的。這條不滿足,動畫無效但程式不會Crash
2.2.1 改變Button
的寬度
例如,想要利用屬性對話來改變一個Button
的寬度。
private void initView() {
Button bt = (Button) findViewById(R.id.bt_button_activity);
bt.setOnClickListener((v) -> performAnimate(bt));
}
private void performAnimate(Button bt) {
ObjectAnimator.ofInt(bt, "width", 500).setDuration(1000).start();
}
實際測試,這段程式碼完全不起作用。
2.2.2不起作用的原因
Button
繼承的TextView
/**
* Makes the TextView exactly this many pixels wide.
* You could do the same thing by specifying this number in the
* LayoutParams.
*
* @see #setMaxWidth(int)
* @see #setMinWidth(int)
* @see #getMinWidth()
* @see #getMaxWidth()
*
* @attr ref android.R.styleable#TextView_width
*/
@android.view.RemotableViewMethod
public void setWidth(int pixels) {
mMaxWidth = mMinWidth = pixels;
mMaxWidthMode = mMinWidthMode = PIXELS;
requestLayout();
invalidate();
}
/**
* Return the width of the your view.
*
* @return The width of your view, in pixels.
*/
@ViewDebug.ExportedProperty(category = "layout")
public final int getWidth() {
return mRight - mLeft;
}
getWidth()
方法View
的方法,是可以獲取Button
高度的。setWidth()
方法TextView
和子類的專屬方法。是用來設定TextView
的最大寬度和最小寬度的,並不是用來設定TextView
的寬度的方法。TextView
的寬度對應於XML
的android:layout_width
,setWidth
方法對應的是android:width
。
也就是說:Button
的setWidth()
和getWidth()
對應的就不是一個屬性。只滿足的條件1,不滿足條件2
2.2.3 解決辦法
有三種解決辦法:
- 如果有許可權,給物件加上
get
和set
方法 - 用一個類包裝原始物件,間接提供
get
和set
方法 - 採用
ValueAnimation
,監聽動畫過程,實現屬性的改變
get
和set
方法往往拿不到許可權。
利用包裝類方法:
private void initView() {
Button bt = (Button) findViewById(R.id.bt_button_activity);
bt.setOnClickListener((v) -> performAnimate(bt,bt.getWidth()));
}
private void performAnimate(Button bt,int width) {
ButtonWrapper wrapper = new ButtonWrapper(bt);
wrapper.setWidth(width);
ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(1000).start();
}
private static class ButtonWrapper {
private View target;
public ButtonWrapper(View target) {
this.target = target;
}
public int getWidth() {
return target.getLayoutParams().width;
}
public void setWidth(int width) {
target.getLayoutParams().width = width;
target.requestLayout();
}
}
拿到Button
的寬度後,設定給ButtonWrapper
。這樣動畫開始後,Button
會從原始大小開始變化。
利用ValueAnimation
方法:
private void initView() {
Button bt = (Button) findViewById(R.id.bt_button_activity);
bt.setOnClickListener((v) -> performAnimate(bt,bt.getWidth(),500));
}
private void performAnimate(Button bt,int start, int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1,100);
//IntEvaluator物件,估值的時候使用
IntEvaluator intEvaluator = new IntEvaluator();
valueAnimator.addUpdateListener((animator -> {
//獲取當前動畫的進度值 , 整型, 1到100
int currentValue = (int) animator.getAnimatedValue();
//獲取當前進度的佔整個動畫過程的比例,浮點型, 0到1
float fraction = animator.getAnimatedFraction();
//直接利用整型估值器,通過比例計算寬度,然後Button設定
bt.getLayoutParams().width = intEvaluator.evaluate(fraction,start,end);
bt.requestLayout();
}));
//開啟動畫
valueAnimator.setDuration(1000).start();
}
監控動畫過程,利用IntEvaluator
估值器
3.最後
動畫基礎知識大概介紹完,自定義TypeEvaluator
和Interpolator
以及配合自定義View
更多高階的用法,以後再做補充。
接下來相當長的時間會用來學習自定義View
。想通過一系列部落格來記錄學習,一開始先學習一些View
的基礎屬性知識為學習自定義View
做準備,再學習具體的測量,繪製過程,View
的事件體系,工作原理。學習過程中間會加入繼續對動畫的深入學習,也可能會加入RxJava
的後續學習或者其他的框架的學習。
相關文章
- Android基礎知識學習Android
- Android基礎知識Android
- 學習下區塊鏈技術基礎知識區塊鏈
- 基礎知識學習筆記筆記
- Android基礎知識:Service(3)啟動模式Android模式
- Android面試之——數學基礎知識Android面試
- 動手學深度學習需要這些數學基礎知識深度學習
- JavaSE基礎知識學習—–多型Java多型
- JavaSE基礎學習知識整理大全Java
- RxJava 學習筆記 -- 基礎知識RxJava筆記
- 怎麼學習基礎知識啊?
- 機器學習基礎知識1機器學習
- go語言學習-基礎知識Go
- JVM學習之JVM基礎知識JVM
- OpenCV與影像處理學習二——影像基礎知識(下)OpenCV
- MySQL 基礎知識梳理學習(四)—-GTIDMySql
- iOS 基礎知識學習目錄索引iOS索引
- 【學習】MySQL基礎知識要點-001MySql
- Android 基礎知識——執行緒Android執行緒
- 學習爬蟲必須學的基礎知識爬蟲
- React學習手記1--基礎知識React
- 使用AngularJS學習MVC的基礎知識分享AngularJSMVC
- HTML5學習之Canvas基礎知識HTMLCanvas
- C++基礎知識學習筆記(1)C++筆記
- 學習網路BGP必備基礎知識
- JavaSE基礎知識學習—–抽象類和介面Java抽象
- C++基礎知識學習筆記(3)C++筆記
- GO 學習筆記 《1. 基礎知識》Go筆記
- mysql資料庫學習基礎知識整理MySql資料庫
- android基礎學習-android篇day13-UI基礎控制元件(下)AndroidUI控制元件
- 安卓(Android)開發基礎知識安卓Android
- Android基礎夯實–重溫動畫(三)之初識Property AnimationAndroid動畫
- 圖形學基礎知識
- Linux shell基礎知識_8(下)Linux
- Python學習筆記—day1—基礎知識Python筆記
- HTML5學習之Web Storage基礎知識HTMLWeb
- 音視訊學習(一)-- 基礎知識準備
- 【python系統學習16】編碼基礎知識Python
- LiteOS學習筆記[01]-weharmonyos-基礎知識筆記