您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)使用ObjectAnimator屬性怎么實(shí)現(xiàn)動畫,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
創(chuàng)建
首先看一下今天所有用到的背景:
寫了一個自定義的View——PointView,用來實(shí)現(xiàn)一個小球的移動效果,PointView代碼如下(可以不用看-。+):
public class PointView extends View { private Point mCurrentPoint; private Paint paint; /** * 兩個構(gòu)造方法 **/ public PointView(Context context) { super(context); paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.CYAN); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); } public PointView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.CYAN); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); } /** * onDraw開始使用畫筆,如果mCurrentPoint為空,就創(chuàng)建Point對象, * 否則就直接調(diào)用drawPoint方法 **/ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mCurrentPoint == null) { mCurrentPoint = new Point(500, 500); drawPoint(canvas); } else { drawPoint(canvas); } } //設(shè)置一個屬性添加的方法 public void setMove(Point point) { mCurrentPoint = point; invalidate(); } //啟動動畫 private void startAnimation() { ObjectAnimator animator = ObjectAnimator.ofObject(PointView.this, "Move", new BallEvaluator(), new Point(500, 500), new Point(500, 800), new Point(700, 800)); animator.setInterpolator(new LinearInterpolator()); animator.setDuration(5000); animator.start(); } //在外部調(diào)用的方法,通過此方法,開啟小球動作的動畫。 public void moveBall() { startAnimation(); } private void drawPoint(Canvas canvas) { canvas.drawCircle(mCurrentPoint.getX(), mCurrentPoint.getY(), 30, paint); } //小球?qū)ο蟮墓乐灯? public class BallEvaluator implements TypeEvaluator<Point> { float x; float y; @Override public Point evaluate(float fraction, Point startValue, Point endValue) { float startX = startValue.getX(); float startY = startValue.getY(); float endX = endValue.getX(); float endY = endValue.getY(); x = fraction * (endX - startX); y = fraction * (endY - startY); Log.e("ASDSAD", "x = " + x + "y = " + y); return new Point(startX + x, startY + y); } } }
代碼可能有點(diǎn)多,不過這不是主要的,我們今天關(guān)注的只是屬性動畫,所以我們只需要看里面的startAnimation方法和setMove方法就好:
setMove:由于我們知道屬性動畫ObjectAnimator類是通過將propertyName拼接成對應(yīng)的set方法,然后通過反射機(jī)制去調(diào)用該方法,所以我們需要有一個對應(yīng)的set方法。
startAnimation:這個方法我們用來設(shè)置我們的動畫以及啟動動畫。setMove方法,很簡單,我們只是將傳入的新的小球?qū)ο筚x值給了mCurrentBall,然后調(diào)用invalidate方法重新繪制。下面看一下startAnimation方法:
ObjectAnimator animator = ObjectAnimator.ofObject(PointView.this, "Move", new BallEvaluator(), new Point(500, 500), new Point(500, 800), new Point(700, 800)); animator.setInterpolator(new LinearInterpolator()); animator.setDuration(5000); animator.start();
我們看一下先進(jìn)入ofObject方法(相信ofObject里面的參數(shù)大家都看得懂):
public static ObjectAnimator ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setObjectValues(values); anim.setEvaluator(evaluator); return anim; }
我們發(fā)現(xiàn)ofObject是一個靜態(tài)方法:他在里面創(chuàng)建了一個ObjectAnimator對象。然后調(diào)用了setObjeectValues和setEvaluator方法,分別添加了數(shù)據(jù)和估值器。
也就是這個ofObject里面有三個入口等著我們進(jìn)去:
ObjectAnimator的構(gòu)造方法
setObjectValues方法
setEvaluator方法
那我們先從ObjectAnimator的構(gòu)造方法開始看吧。
ObjectAnimator構(gòu)造方法:
private ObjectAnimator(Object target, String propertyName) { setTarget(target); setPropertyName(propertyName); }
又是兩個方法,一個一個去看,先進(jìn)入setTarget:
@Override public void setTarget(@Nullable Object target) { final Object oldTarget = getTarget(); if (oldTarget != target) { if (isStarted()) { cancel(); } mTarget = target == null ? null : new WeakReference<Object>(target); // New target should cause re-initialization prior to starting mInitialized = false; } }
這些代碼都能夠知道什么意思,這個方法我們只需要注意兩點(diǎn):
我們將傳入的target傳給了mTarget這個弱引用。
mInitialized = false;這個屬性我們可以這么理解,在他的ObjectAnimator沒有準(zhǔn)備就緒(初始化過程尚未完成時),他一直都是false。
這個方法跳過。
然后我們看setPropertyName方法:
public void setPropertyName(@NonNull String propertyName) { // mValues could be null if this is being constructed piecemeal. Just record the // propertyName to be used later when setValues() is called if so. if (mValues != null) { PropertyValuesHolder valuesHolder = mValues[0]; String oldName = valuesHolder.getPropertyName(); valuesHolder.setPropertyName(propertyName); mValuesMap.remove(oldName); mValuesMap.put(propertyName, valuesHolder); } mPropertyName = propertyName; // New property/values/target should cause re-initialization prior to starting mInitialized = false; }
首先介紹一下mValues和mValuesMap這兩個屬性,他們都是存儲PropertyValueHolder的屬性,而且儲存的都一樣,只是mValuesMap可以讓我們通過propertyName來查找對應(yīng)的PropertyValueHolder。
PropertyValuesHolder[] mValues; HashMap<String, PropertyValuesHolder> mValuesMap;
這個方法只是將propertyName放入PropertyValueHolder中(具體邏輯如上,先判斷mValues是否為空,如果不為空就將propertyName放入mValues和mValuesMap中,最后將propertyName賦值給mPropertyName),可以過了。
現(xiàn)在我們的ObjectAnimator構(gòu)造方法看完了,我們接著看setObjectValues方法:
anim.setObjectValues:
@Override public void setObjectValues(Object... values) { if (mValues == null || mValues.length == 0) { // No values yet - this animator is being constructed piecemeal. Init the values with // whatever the current propertyName is if (mProperty != null) { setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator) null, values)); } else { setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator) null, values)); } } else { super.setObjectValues(values); } }
這段代碼的總體邏輯只有一個:如果mValues沒有值,那么就調(diào)用setValues方法,否則就調(diào)用父類的setObjectValues方法。
感覺很亂啊,穩(wěn)??! 我們這是第一次創(chuàng)建的對象,所以肯定是為空的,所以我們只需要看setValues方法就好了,但是注意,這里還有PropertyValueHolder,所以我們決定先看一下PropertyValueHolder的ofObject方法:
PropertyValueHolder.ofObject:
public static <V> PropertyValuesHolder ofObject(Property property, TypeEvaluator<V> evaluator, V... values) { PropertyValuesHolder pvh = new PropertyValuesHolder(property); pvh.setObjectValues(values); pvh.setEvaluator(evaluator); return pvh; }
跟上面ObjectAnimator的ofObject差異不多,我們就不多說了,有兩條路可以選:
setObjectValues
setEvaluator
先看setObjectValues:
PropertyValueHolder.setObjectValues:
public void setObjectValues(Object... values) { mValueType = values[0].getClass(); mKeyframes = KeyframeSet.ofObject(values); if (mEvaluator != null) { mKeyframes.setEvaluator(mEvaluator); } }
我知道大家都快吐了,現(xiàn)在KeyFrames又出來了,頭皮發(fā)麻對吧,穩(wěn)住,我們堅持住!
這個KeyFrames是KeyFrameSet的接口,我們看一下KeyframeSet的ofObject方法:
KeyframeSet.ofObject方法:
public static KeyframeSet ofObject(Object... values) { int numKeyframes = values.length; ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];//創(chuàng)建了一個至少為兩位的ObjectKeyFrame對象 if (numKeyframes == 1) { keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f); keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]); } else { keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]); for (int i = 1; i < numKeyframes; ++i) { keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]); } } return new KeyframeSet(keyframes); }
我們終于看到了一個比較熟悉的類,KeyFrame,這個叫做關(guān)鍵幀的類終于出現(xiàn)了,我們簡單分析一下這個方法:
首先創(chuàng)建了一個至少為兩位的ObjectKeyFrame對象,然后對values的長度進(jìn)行判斷,如果只有一個值,那么就將唯一的一個值添加到最后一位(此時也就是第二位),否則就依次添加。最后將ObjectKeyFrame的數(shù)組轉(zhuǎn)換成KeyFrameSet類型返回。
現(xiàn)在我們回到PropertyValueHolder的setObjectValues方法中,接下來我們要看一下setEvaluator方法(需要在KeyFrameSet中查看)
KeyFrameSet.setEvaluator方法:
public void setEvaluator(TypeEvaluator evaluator) { mEvaluator = evaluator; }
這個不用多說,直接過。
現(xiàn)在我們的PropertyValueHolder的ofObject方法已經(jīng)看完了,我們跳回anim.setObjectValues方法,看一下setValues方法:
setValues:
public void setValues(PropertyValuesHolder... values) { int numValues = values.length; mValues = values; mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); for (int i = 0; i < numValues; ++i) { PropertyValuesHolder valuesHolder = values[i]; mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); } // New property/values/target should cause re-initialization prior to starting mInitialized = false; }
這個完全就是我們剛才說的儲存PropertyValueHolder的兩個屬性mValues和mValuesMap添加數(shù)據(jù)的過程,過。
現(xiàn)在我們只差最后一個大方法了,anim.setEvaluator了,激動?。?!
anim.setEvaluator方法:
public void setEvaluator(TypeEvaluator value) { if (value != null && mValues != null && mValues.length > 0) { mValues[0].setEvaluator(value); } }
這個方法是給每個PropertyValueHolder對象都執(zhí)行setEvaluator方法,我們點(diǎn)進(jìn)去這個方法看一下:
PropertyValueHolder.setEvaluator方法:
public void setEvaluator(TypeEvaluator evaluator) { mEvaluator = evaluator; mKeyframes.setEvaluator(evaluator); }
又進(jìn)入了Keyframes的setEvaluator,我們接著看一下KeyFrameSet的setEvaluator方法:
KeyFrameSet.setEvaluator方法:
public void setEvaluator(TypeEvaluator evaluator) { mEvaluator = evaluator; }
這個方法不用說了。
最后我們返回了創(chuàng)建的anim的對象,到現(xiàn)在為止,我們得到我們想要的ObjectAnimator對象了。
這個過程是有點(diǎn)繁瑣,我們現(xiàn)在屢一下思路:
調(diào)用了ObjectAnimator.ofObject之后
首先new一個ObjectAnimator對象,進(jìn)入ObjectAnimator的構(gòu)造方法中:在構(gòu)造方法中,我們執(zhí)行了兩個方法:setTarget和setPropertyName。
然后調(diào)用了ObjectAnimator的setObjectValues方法:在這個方法中我們首先實(shí)例化了PropertyValueHolder對象,然后調(diào)用setValues方法將PropertyValueHolder傳入。
之后調(diào)用了ObjectAnimator的setEvaluator方法:添加了估值器。
最后返回了ObjectAnimator對象。
到這里我們就完成了ObjectAnimator對象實(shí)例的創(chuàng)建。
到這里創(chuàng)建部分就全部完成了,接下來我們看一下添加屬性,這個就很簡單了。
添加屬性
我們就舉一個方法為例吧,拿setInterpolator方法為例:
public void setInterpolator(TimeInterpolator value) { if (value != null) { mInterpolator = value; } else { mInterpolator = new LinearInterpolator(); } }
這個方法是我們添加插值器的方法,我們注意到他只是給mInterpolator賦值而已,如果傳入為空,則添加線性插值器。
其他的添加屬性的方法,像setDuration、setRepeatCount等都是如此,大家下去就自己看一下吧。
由于還不會用 starUML,所以現(xiàn)在還沒發(fā)畫一張時序圖(只是手畫的,估計大家也不想看哈哈),等學(xué)完UML之后會給大家補(bǔ)上的,希望這篇文章大家喜歡。
以上就是使用ObjectAnimator屬性怎么實(shí)現(xiàn)動畫,小編相信有部分知識點(diǎn)可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。