文章首發(fā)于個人博客
任何形式的轉載都請聯(lián)系作者獲得授權并注明出處。
一铝宵、基本概念
屬性動畫就是在一定時間間隔內(nèi),通過不斷對值進行改變,并不斷將該值賦給對象的屬性鹏秋,從而實現(xiàn)該對象在該屬性上的動畫效果尊蚁。
二、動畫
1侣夷、View中的方法
我們可以對View調(diào)用以下屬性實現(xiàn)動畫
View中的方法 | 功能 |
---|---|
setTranslationX() 横朋、setTranslationY() 、setTranslationZ()
|
設置X百拓、Y琴锭、Z軸平移 |
setX() 、setX() 衙传、setX()
|
設置X祠够、Y、Z軸絕對位置 |
setRotation() 粪牲、setRotationX() 古瓤、setRotationY()
|
設置平面、X腺阳、Y軸旋轉 |
setScaleX() 落君、setScaleY()
|
設置X、Y方向縮放 |
setAlpha() |
設置透明度 |
2亭引、ValueAnimator
屬性動畫機制中最核心的一個類绎速,ObjectAnimator和ViewPropertyAnimator都是通過這個這個實現(xiàn)的。ValueAnimator是通過不斷控制值的變化焙蚓,再不斷添加屬性纹冤,從而實現(xiàn)動畫效果
使用方法
- 初始化ValueAnimator,設置各種屬性
- 給ValueAnimator設置監(jiān)聽器购公,通過getAnimatedValue()拿到變化值后更新控件萌京。
常用方法 | 功能 |
---|---|
ofInt() |
返回一個int型變化的ValueAnimator |
ofFloat() |
返回一個float型變化的ValueAnimator |
ofObject |
返回一個object型變化的ValueAnimator。 |
1.1宏浩、設置顏色變化
我們這里并沒有使用ofArgb
這個屬性知残,因為這個方法是在API21以上使用的,在低版本上不兼容比庄。
final View view = findViewById(R.id.view);
//以整型數(shù)值的形式求妹,過渡到結束值
ValueAnimator animator = ValueAnimator.ofInt(0xffff00ff, 0xffffff00, 0xffff00ff);
//設置求值器
animator.setEvaluator(new ArgbEvaluator());
//設置動畫的播放時長
animator.setDuration(1000);
//設置動畫重復播放次數(shù),ValueAnimator.INFINITE為無限重復
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue();
Log.i(TAG, "onAnimationUpdate: "+currentValue);
view.setBackgroundColor(currentValue);
view.requestLayout();
}
});
animator.start();
1.2、ofObject()
的使用
ofInt和ofFloat是針對Int值和Float值的變化佳窑,但是制恍,我們只能控制一個值的變化,但是當我們需要實現(xiàn)多值變化時神凑,它們就不再滿足我們的需求净神。
//設置變化的值
ValueObject startObjectVal = new ValueObject(1f, 0);
ValueObject endObjectVal = new ValueObject(0f, 360);
ValueAnimator animator = ValueAnimator.ofObject(new Evaluator(), startObjectVal, endObjectVal);
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setAlpha(((ValueObject) animation.getAnimatedValue()).alphaValue);
//可以設置各種動畫
view.setRotation(((ValueObject) animation.getAnimatedValue()).rotateValue);
view.requestLayout();
}
});
animator.start();
》》設置估值器,估值器的作用覺得值得變化順序《《
//下面具體講解
class Evaluator implements TypeEvaluator<ValueObject> {
@Override
public ValueObject evaluate(float fraction, ValueObject startValue, ValueObject endValue) {
float alphaValue = startValue.alphaValue + (endValue.alphaValue - startValue.alphaValue) * fraction;
float rotateValue = startValue.rotateValue + (endValue.rotateValue - startValue.rotateValue) * fraction;
return new ValueObject(alphaValue, rotateValue);
}
}
//創(chuàng)建對象,保存透明度和旋轉的值得變化
class ValueObject {
float alphaValue;//透明度
float rotateValue;//旋轉
ValueObject(float alphaValue, float rotateValue) {
this.alphaValue = alphaValue;
this.rotateValue = rotateValue;
}
}
1.3强挫、屬性和方法整理
常用的屬性
方法 | 解釋 | 方法 | 解釋 |
---|---|---|---|
setDuration |
設置動畫總時長,單位毫秒薛躬。 | getDuration |
獲取動畫總時長 |
setFrameDelay |
設置每一幀之間間隔多少毫秒 | getFrameDelay |
獲取每一幀之間間隔多少毫秒 |
setInterpolator |
設置動畫的插值器 | getInterpolator |
獲取當前使用的插值器 |
setRepeatCount |
設置重復次數(shù) | getRepeatCount |
獲取重復次數(shù) |
setRepeatMode |
設置重復模式俯渤。有RESTART(正序)和REVERSE(倒序) | getRepeatMode |
獲取重復模式 |
setStartDelay |
設置開始前延遲毫秒數(shù) | getStartDelay |
獲取開始前延遲毫秒數(shù) |
getAnimatedValue |
獲取計算出來的當前屬性值 | getAnimatedValue |
獲取計算出來的當前某個屬性的值 |
setEvaluator |
設置求值器 | setFloatValues |
設置Float型變化值,設置初始值型宝、中間值八匠、結束值 |
setIntValues |
設置Int型變化值,設置初始值趴酣、中間值梨树、結束值 | setObjectValues |
設置Object型變化值,設置初始值岖寞、中間值抡四、結束值 |
常用的方法
方法 | 解釋 | 方法 | 解釋 |
---|---|---|---|
addUpdateListener |
添加值變化監(jiān)聽器 | addUpdateListener |
添加動畫狀態(tài)監(jiān)聽器 |
start |
開始動畫 | pause |
暫停動畫 |
resume |
繼續(xù)動畫 | cancel |
取消動畫 |
end |
動畫結束 | reverse |
倒序播放動畫 |
isRunning |
判斷是否在正在運行 | isStarted |
判斷是的開始播放 |
1.4、估值器和插值器(重點)
估值器--TypeEvaluator:決定值的具體變化順序
估值器的使用我們上面已經(jīng)學習過了仗谆,在這里對估值器的具體使用簡單的解釋指巡。
//實現(xiàn)了TypeEvaluator接口
public class FloatEvaluator implements TypeEvaluator {
/**
* fraction:表示動畫完成度
* startValue:動畫的初始值
* endValue:動畫的結束值
* /
public Object evaluate(float fraction, Object startValue, Object endValue) {
//用初始值加上動畫完成度乘以結束值和初始值之間的差值
}
}
插值器--Interpolator:決定值的速度變化順序
使用方法:
setInterpolator(Interpolator interpolator)//設置速度插值器
常用的插值器:
- LinearInterpolator:線性勻速變化
- AccelerateDecelerateInterpolator:先加速再減速
- AccelerateInterpolator:持續(xù)加速
- DecelerateInterpolator:持續(xù)減速直到 0
- AnticipateInterpolator:先回拉一下再進行正常動畫軌跡
- OvershootInterpolator:動畫會超過目標值一些,然后再彈回來
- AnticipateOvershootInterpolator:先回拉一下再進行正常動畫軌跡隶垮,最后動畫會超過目標值一些藻雪,然后再彈回來
- BounceInterpolator:在目標值來回跳動
3、ObjectAnimator
直接對對象的屬性值進行改變操作狸吞,從而實現(xiàn)動畫效果勉耀,內(nèi)部是有ValueAnimator實現(xiàn),因此其也有ofXXX()方法蹋偏,這里接受的參數(shù)不一樣了便斥,具體的就不整理了,常用屬性和常用方法和ValueAnimator一致
使用方法:
- 對于自定義控件威始,使用
setter
/getter
方法椭住; - 調(diào)用
ObjectAnimator.ofXXX()
創(chuàng)建ObjectAnimator
對象,設置常用屬性字逗。 - 調(diào)用
start()
方法執(zhí)行動畫
方法:ofFloat(Object target, String propertyName, float... values)
參數(shù):
target:我們需要控制動畫的對象
-
propertyName:設置動畫效果(傳入任意屬性值)
這里傳入的參數(shù)京郑,其實是調(diào)用了
ValueAnimator
的setXXX()
方法和getXXX()
方法,具體的代碼就不貼了葫掉。-
alpha
:透明度 -
rotation
些举,RotationX
,RotationY
:旋轉 -
translationX
俭厚,translationY
:平移 -
ScaleX
户魏,scaleY
:縮放 - values:自定義屬性
-
values
:值
》》自定義圓形進度條《《
完整代碼在線地址:Github在線地址
ProPress.java
我們在Activity中,給動畫設置了一個屬性
progress
,我們在ProPress.java
中,用getProgress()
和setProgress
方法叼丑,這樣系統(tǒng)會自動調(diào)用該對象屬性的set() & get()方法進行賦值关翎。
/**
* Created by Active_Loser on 2018/10/22.
* Content: 自定義圓形進度條
*/
public class ProPress extends View {
//.....
private int progress = 0;
public float getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
invalidate();
}
//.....
@Override
protected void onDraw(Canvas canvas) {
int width = getWidth();
int height = getHeight();
//繪制圓弧
RectF arcRectF = new RectF(20, 20, width-20, height-20);
//progress設置值為0-100,因此需要乘3.6
canvas.drawArc(arcRectF, 135, progress * 3.6f, false, mArcPaint);
canvas.drawText(progress + "%", width/2, height/2-(mArcPaint.ascent() + mArcPaint.descent()) / 2, mTextPaint);
}
}
XML:
<com.example.active.loser.views.level3.ProPress
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerInParent="true"
android:id="@+id/view"/>
Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ProPress view = findViewById(R.id.view);
// 創(chuàng)建 ObjectAnimator 對象
ObjectAnimator animator = ObjectAnimator.ofInt(view, "progress", 0, 100);
//持續(xù)時長4秒
animator.setDuration(4000);
animator.setInterpolator(new FastOutSlowInInterpolator());
animator.start();
}
4鸠信、ViewPropertyAnimator
ValueAnimator纵寝、ObjectAnimator、ViewPropertyAnimator三者使用難度和靈活性逐漸遞減星立,因此我們盡量選擇簡單的使用
使用方法
view.animate().動畫();
常用的動畫如下表所示:
View中的方法 | 對于中的方法ViewPropertyAnimator | 功能 |
---|---|---|
setTranslationX() |
translationX() 爽茴、translationXBy() 、 |
設置X軸平移 |
setTranslationY() |
translationY() 绰垂、translationYBy()
|
設置Y軸平移 |
setTranslationZ() |
translationZ() 室奏、translationZBy()
|
設置Z軸平移 |
setX() 、setX() 劲装、setX()
|
x() 胧沫、xBy() 、y() 占业、yBy() 琳袄、z() 、zBy()
|
設置X纺酸、Y窖逗、Z軸絕對位置 |
setRotation() |
rotation() 、rotationBY()
|
設置平面軸旋轉 |
setRotationX() |
rotationX() 餐蔬、rotationXBy()
|
設置X軸旋轉 |
setRotationY() |
rotationY() 碎紊、rotationYBy()
|
設置Y軸旋轉 |
setScaleX() |
scaleX() 、scaleX()By
|
設置X方向縮放 |
setScaleY() |
scaleY() 樊诺、scaleYBy()
|
設置Y方向縮放 |
setAlpha() |
alpha() 仗考、alphaBy()
|
設置透明度 |
特點:
-
有
by
:變化偏移、無by
:變化到即:加上By的意思是词爬,繼續(xù)動畫這么多數(shù)值秃嗜,不加By的意思是動畫到這個數(shù)值。
簡單的使用:
view.animate()
.setDuration(5000)
.zBy(10)
.setInterpolator(new BounceInterpolator())
.setStartDelay(1000)
.withLayer()//是否開啟硬件加速
//監(jiān)聽
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
})
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
}
})
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
.start();