編輯:關於Android編程
ValueAnimator:對值進行平滑的動畫過渡。繼承Animator抽象類
ObjectAnimator:對任意對象的任意屬性進行動畫操作。繼承自ValueAnimator
1、Animator源碼解析
給所有動畫提供基本支持類,是一個抽象類。
啟動動畫。如果startDelay的值非零,動畫會在延時過後開始。如果沒有設置延時值,則會馬上啟動動畫。動畫在調用該方法的線程上運行。
public void start() { }
取消動畫。和end()不一樣,取消動畫是停止在其運行軌道上,並回調給android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)。此方法必須在運行動畫的線程調用。
public void cancel() { }
public void end() { }
public void pause() { if (isStarted() && !mPaused) {//動畫正在運行並且暫停狀態是false mPaused = true; if (mPauseListeners != null) { ArrayList tmpListeners = (ArrayList) mPauseListeners.clone(); int numListeners = tmpListeners.size(); for (int i = 0; i < numListeners; ++i) { tmpListeners.get(i).onAnimationPause(this); } } } }
重啟暫停的動畫。調用該方法的線程必須和動畫開始的線程是同一個。調用該方法並且有效的前提是pause()生效之後的調用。
public void resume() { if (mPaused) { mPaused = false; if (mPauseListeners != null) { ArrayList tmpListeners = (ArrayList) mPauseListeners.clone(); int numListeners = tmpListeners.size(); for (int i = 0; i < numListeners; ++i) { tmpListeners.get(i).onAnimationResume(this); } } } }
public boolean isPaused() { return mPaused; }
public abstract long getStartDelay();
public abstract void setStartDelay(long startDelay);
public abstract Animator setDuration(long duration);
public abstract long getDuration();
AccelerateDecelerateInterpolator 在動畫開始與結束的地方速率改變比較慢,在中間的時候加速
AccelerateInterpolator 在動畫開始的地方速率改變比較慢,然後開始加速
AnticipateInterpolator 開始的時候向後然後向前甩
AnticipateOvershootInterpolator 開始的時候向後然後向前甩一定值後返回最後的值
BounceInterpolator 動畫結束的時候彈起
CycleInterpolator 動畫循環播放特定的次數,速率改變沿著正弦曲線
DecelerateInterpolator 在動畫開始的地方快然後慢
LinearInterpolator 以常量速率改變
OvershootInterpolator 向前甩一定值後再回到原來位置
也可以自定義。
public abstract void setInterpolator(TimeInterpolator value);
獲取當前運行的動畫的變化率,如果直接get獲取,得到的是null,因為Animatior中沒有實現TimeInterpolator接口。注意:TimeInterpolator是一個接口類。
public TimeInterpolator getInterpolator() { return null; }當前動畫是否正在運行。true:正在運行。false:有可能停止或暫停或未開始。
public abstract boolean isRunning();
當前動畫是否開始運行並且運行還未結束。實際上返回的是isRunning()的值,因為如果設置了延遲,延遲時間還未結束,動畫還未進行,isStarted()會返回true。但是在延遲時間內,動畫還沒有開始,isRunning()的值只會在延遲結束後返回true,只有當動畫真正運行了,才會返回true。所以isStarted()實際調用isRunning()更准確。
public boolean isStarted() { // Default method returns value for isRunning(). Subclasses should override to return a // real value. return isRunning(); }
給當前動畫添加監聽器,或者說是接收一個監聽器,只要實現listener監聽器的方法就可以實現對動畫的各種監聽了。
ArrayList mListeners = null; // start,end,cancel,repeat回調
ArrayList mPauseListeners = null; // pause, resume回調
ArrayList mUpdateListeners = null; // value更新回調
public void addListener(AnimatorListener listener) { if (mListeners == null) { mListeners = new ArrayList(); } mListeners.add(listener);//添加到監聽組中 }
從當前動畫的監聽組中移除指定動畫監聽器。
public void removeListener(AnimatorListener listener) { if (mListeners == null) { return; } mListeners.remove(listener); if (mListeners.size() == 0) { mListeners = null; } }
public ArrayList getListeners() { return mListeners; }給當前動畫添加暫停監聽器。
public void addPauseListener(AnimatorPauseListener listener) { if (mPauseListeners == null) { mPauseListeners = new ArrayList(); } mPauseListeners.add(listener); }
public void removePauseListener(AnimatorPauseListener listener) { if (mPauseListeners == null) { return; } mPauseListeners.remove(listener); if (mPauseListeners.size() == 0) { mPauseListeners = null; } }
public void removeAllListeners() { if (mListeners != null) { mListeners.clear(); mListeners = null; } if (mPauseListeners != null) { mPauseListeners.clear(); mPauseListeners = null; } }
2、ValueAnimator類
使用時間循環機制計算值與值之間的動畫過渡。同時負責管理動畫的播放次數、播放模式、對動畫設置監聽等。運行在一個自定義的handler上,以確保動畫的屬性的改變是運行在UI線程上。動畫的實現可以直接用代碼實現和用xml文件實現。xml文件實現動畫可以大限度實現復用性。
內部變量mPlayingState可能值,以表示動畫當前的狀態。
static final int STOPPED = 0; // Not yet playing static final int RUNNING = 1; // Playing normally static final int SEEKED = 2; // Seeked to some time value默認的動畫效果。在動畫開始的時候加速後減速
private static final TimeInterpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator();
public ValueAnimator() { }
構造並返回一個int類型的動畫的ValueAnimator。一般創建一個對象都是構造函數。顯示創建一個ValueAnimator對象,可以使用比如:ValueAnimator anim= ValueAnimator.ofInt(0,2);。因為ofInt方法內部調用了空構造函數。ValueAnimator是計算值與值之間的平滑過渡動畫,所以通常會傳入兩個及以上的值,不會是單一參數。
如果只有一個值,則作為動畫的終點值,如果有兩個值,則作為動畫的開始值和終點值,如果有兩個以上的,就作為開始值,中間值,終點值,且分布在動畫的過程中。
public static ValueAnimator ofInt(int... values) { ValueAnimator anim = new ValueAnimator(); anim.setIntValues(values); return anim; }
public static ValueAnimator ofArgb(int... values) { ValueAnimator anim = new ValueAnimator(); anim.setIntValues(values); anim.setEvaluator(ArgbEvaluator.getInstance()); return anim; }
public static ValueAnimator ofFloat(float... values) { ValueAnimator anim = new ValueAnimator(); anim.setFloatValues(values); return anim; }屬性值之間的平滑過渡動畫。或者說是PropertyValuesHolder對象之間過渡的動畫。PropertyValuesHolder是一個跟屬性有關的類。
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) { ValueAnimator anim = new ValueAnimator(); anim.setValues(values); return anim; }
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) { ValueAnimator anim = new ValueAnimator(); anim.setObjectValues(values); anim.setEvaluator(evaluator); return anim; }
以下是IntEvaluator實現的方法,evaluate方法中的具體實現,其值之間的計算遵循方程result = x0+t*(x1-x0)
public Integer evaluate(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); }
public void setIntValues(int... values) { if (values == null || values.length == 0) { return; } if (mValues == null || mValues.length == 0) { setValues(PropertyValuesHolder.ofInt("", values)); } else { PropertyValuesHolder valuesHolder = mValues[0]; valuesHolder.setIntValues(values); } // New property/values/target should cause re-initialization prior to starting mInitialized = false; }設置動畫float類型初始值。如果在ofFloat時候傳入多個參數,則在調用setFloatValues時覆蓋在ofFloat傳入的第一個值,以此類推。
public void setFloatValues(float... values) { if (values == null || values.length == 0) { return; } if (mValues == null || mValues.length == 0) { setValues(PropertyValuesHolder.ofFloat("", values)); } else { PropertyValuesHolder valuesHolder = mValues[0]; valuesHolder.setFloatValues(values); } // New property/values/target should cause re-initialization prior to starting mInitialized = false; }
public void setObjectValues(Object... values) { if (values == null || values.length == 0) { return; } if (mValues == null || mValues.length == 0) { setValues(PropertyValuesHolder.ofObject("", null, values)); } else { PropertyValuesHolder valuesHolder = mValues[0]; valuesHolder.setObjectValues(values); } // New property/values/target should cause re-initialization prior to starting mInitialized = false; }
public void setValues(PropertyValuesHolder... values) { int numValues = values.length; mValues = values; mValuesMap = new HashMap(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; }
public PropertyValuesHolder[] getValues() { return mValues; }
@CallSuper void initAnimation() { if (!mInitialized) { int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { mValues[i].init(); } mInitialized = true; } }
@Override public ValueAnimator setDuration(long duration) { if (duration < 0) { throw new IllegalArgumentException("Animators cannot have negative duration: " + duration); } mUnscaledDuration = duration; updateScaledDuration(); return this; }
private static float sDurationScale = 1.0f;
// How long the animation should last in ms private long mDuration = (long)(300 * sDurationScale); private long mUnscaledDuration = 300;
private void updateScaledDuration() {//格式轉換 mDuration = (long)(mUnscaledDuration * sDurationScale); }
獲得動畫持續時間。
@Override public long getDuration() { return mUnscaledDuration; }
public void setCurrentPlayTime(long playTime) { float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1; setCurrentFraction(fraction); }
設置指定的動畫進度。fraction值為0時,定位到動畫的開始時刻,值為1時,定位到動畫的結束點,如果fraction值為2,表示動畫重復了1此,且定位到反向動畫的結束點。如果動畫還未開始,setCurrentFraction的設置並不會改變動畫的狀態,如果動畫已經開始了,調用setCurrentFraction,動畫會從設置的點開始繼續運行。fraction的改變不會回調給AnimatorListener監聽。
public static final int INFINITE = -1;表示無限次重復
private int mRepeatCount = 0;動畫重復的次數。
private boolean mPlayingBackwards = false;//表示當前動畫是否是在反向播放,就是倒帶。
public static final int REVERSE = 2;//動畫重復模式,當動畫播放結束且重復次數是一個正值或無限,則對迭代動畫方向取反,就是動畫方向倒帶。
當repeatMode=REVERSE,每個動畫周期反轉一次
public void setCurrentFraction(float fraction) { initAnimation(); if (fraction < 0) { fraction = 0; } int iteration = (int) fraction; if (fraction == 1) { iteration -= 1; } else if (fraction > 1) { if (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE) { if (mRepeatMode == REVERSE) { mPlayingBackwards = (iteration % 2) != 0; } fraction = fraction % 1f; } else { fraction = 1; iteration -= 1; } } else { mPlayingBackwards = mReversing; } mCurrentIteration = iteration; long seekTime = (long) (mDuration * fraction); long currentTime = AnimationUtils.currentAnimationTimeMillis(); mStartTime = currentTime - seekTime; mStartTimeCommitted = true; // do not allow start time to be compensated for jank if (mPlayingState != RUNNING) { mSeekFraction = fraction; mPlayingState = SEEKED; } if (mPlayingBackwards) { fraction = 1f - fraction; } animateValue(fraction); }
public long getCurrentPlayTime() { if (!mInitialized || mPlayingState == STOPPED) { return 0; } return AnimationUtils.currentAnimationTimeMillis() - mStartTime; }
獲取延遲時間,毫秒數
@Override public long getStartDelay() { return mUnscaledStartDelay; }
@Override public void setStartDelay(long startDelay) { this.mStartDelay = (long)(startDelay * sDurationScale); mUnscaledStartDelay = startDelay; }
獲取每個幀之間動畫的延遲時間。但是幀之間的實際延遲是不同的,取決於系統的負載和能力。
public static long getFrameDelay() { return Choreographer.getFrameDelay(); }
public static void setFrameDelay(long frameDelay) { Choreographer.setFrameDelay(frameDelay); }
public Object getAnimatedValue() { if (mValues != null && mValues.length > 0) { return mValues[0].getAnimatedValue(); } // Shouldn't get here; should always have values unless ValueAnimator was set up wrong return null; }
根據屬性名獲取動畫值。在監聽器AnimatorUpdateListener中回調。
public Object getAnimatedValue(String propertyName) { PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName); if (valuesHolder != null) { return valuesHolder.getAnimatedValue(); } else { // At least avoid crashing if called with bogus propertyName return null; } }
public void setRepeatCount(int value) { mRepeatCount = value; }
public int getRepeatCount() { return mRepeatCount; }
設置動畫重復模式。和設置動畫重復次數配合使用
ValueAnimator.RESTART:從頭播放,默認值
ValueAnimator.REVERSE:反向播放。
public void setRepeatMode(int value) { mRepeatMode = value; }
public int getRepeatMode() { return mRepeatMode; }
添加監聽器。
public void addUpdateListener(AnimatorUpdateListener listener) { if (mUpdateListeners == null) { mUpdateListeners = new ArrayList(); } mUpdateListeners.add(listener); }
移除所有監聽器
public void removeAllUpdateListeners() { if (mUpdateListeners == null) { return; } mUpdateListeners.clear(); mUpdateListeners = null; }
移除指定的AnimatorUpdateListener監聽器。
public void removeUpdateListener(AnimatorUpdateListener listener) { if (mUpdateListeners == null) { return; } mUpdateListeners.remove(listener); if (mUpdateListeners.size() == 0) { mUpdateListeners = null; } }
設置插值器。例如加速器、先加速後減速、自定義插值器等。
@Override public void setInterpolator(TimeInterpolator value) { if (value != null) { mInterpolator = value; } else { mInterpolator = new LinearInterpolator(); } }
@Override public TimeInterpolator getInterpolator() { return mInterpolator; }
設置估值器。
估值器就是系統告訴動畫如何從初始值到結束值的過渡。例如ofFloat()就是通過FloatEvaluator估值器使得初始值到結束值的平滑過渡。
public void setEvaluator(TypeEvaluator value) { if (value != null && mValues != null && mValues.length > 0) { mValues[0].setEvaluator(value); } }
FloatEvaluator實現TypeEvaluator接口,並重寫了evaluate方法,以下是FloatEvaluator具體實現的方法
public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); }fraction表示動畫的完成度,是一個比例值,startValue和endValue表示初始值和結束值。FloatEvaluator估值器計算得到動畫值就是結束值減去初始值再乘以fraction系數再加上初始值。估值器計算得到的值就是當前動畫的值。而fraction就是插值器計算出來的。
ValueAnimator有三種方法可以對值進行操作,ofFloat、ofInt、ofObject。ofFloat估值器對應FloatEvaluator,ofInt的估值器對應IntEvaluator。這兩個估值器的函數都一樣,只是操作的數值類型不一樣。而ofObject是用於對任意對象的操作,估值器就可以使用我們自定義的。自定義估值器就很好玩了,可以根據自己想要的效果來寫一個函數。
顧名思義,就是開始動畫。ValueAnimator繼承了Animator,ValueAnimator具體實現了Animator的抽象方法start。
@Override public void start() { start(false); }以下是start具體實現的代碼,大部分是一些動畫相關值得初始化,值初始化之後真正調用動畫的是animationHandler.start();
private void start(boolean playBackwards) { if (Looper.myLooper() == null) { throw new AndroidRuntimeException("Animators may only be run on Looper threads"); } mReversing = playBackwards; mPlayingBackwards = playBackwards; if (playBackwards && mSeekFraction != -1) { if (mSeekFraction == 0 && mCurrentIteration == 0) { // special case: reversing from seek-to-0 should act as if not seeked at all mSeekFraction = 0; } else if (mRepeatCount == INFINITE) { mSeekFraction = 1 - (mSeekFraction % 1); } else { mSeekFraction = 1 + mRepeatCount - (mCurrentIteration + mSeekFraction); } mCurrentIteration = (int) mSeekFraction; mSeekFraction = mSeekFraction % 1; } if (mCurrentIteration > 0 && mRepeatMode == REVERSE && (mCurrentIteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) { // if we were seeked to some other iteration in a reversing animator, // figure out the correct direction to start playing based on the iteration if (playBackwards) { mPlayingBackwards = (mCurrentIteration % 2) == 0; } else { mPlayingBackwards = (mCurrentIteration % 2) != 0; } } int prevPlayingState = mPlayingState; mPlayingState = STOPPED; mStarted = true; mStartedDelay = false; mPaused = false; updateScaledDuration(); // in case the scale factor has changed since creation time AnimationHandler animationHandler = getOrCreateAnimationHandler(); animationHandler.mPendingAnimations.add(this); if (mStartDelay == 0) { // This sets the initial value of the animation, prior to actually starting it running if (prevPlayingState != SEEKED) { setCurrentPlayTime(0); } mPlayingState = STOPPED; mRunning = true; notifyStartListeners(); } animationHandler.start(); }
取消動畫。
@Override public void cancel() { // Only cancel if the animation is actually running or has been started and is about // to run AnimationHandler handler = getOrCreateAnimationHandler(); if (mPlayingState != STOPPED || handler.mPendingAnimations.contains(this) || handler.mDelayedAnims.contains(this)) { // Only notify listeners if the animator has actually started if ((mStarted || mRunning) && mListeners != null) { if (!mRunning) { // If it's not yet running, then start listeners weren't called. Call them now. notifyStartListeners(); } ArrayList tmpListeners = (ArrayList) mListeners.clone(); for (AnimatorListener listener : tmpListeners) { listener.onAnimationCancel(this); } } endAnimation(handler); } }
@Override public void end() { AnimationHandler handler = getOrCreateAnimationHandler(); if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) { // Special case if the animation has not yet started; get it ready for ending mStartedDelay = false; startAnimation(handler); mStarted = true; } else if (!mInitialized) { initAnimation(); } animateValue(mPlayingBackwards ? 0f : 1f); endAnimation(handler); }
如果動畫為完成前被pause了,調用resume方法,動畫會從停下的點重新開始。如果動畫已經結束或未開始,調用resume將被忽略
@Override public void resume() { if (mPaused) { mResumed = true; } super.resume(); }
@Override public void pause() { boolean previouslyPaused = mPaused; super.pause(); if (!previouslyPaused && mPaused) { mPauseTime = -1; mResumed = false; } }
@Override public boolean isRunning() { return (mPlayingState == RUNNING || mRunning); }
@Override public boolean isStarted() { return mStarted; }
@Override public void reverse() { mPlayingBackwards = !mPlayingBackwards; if (mPlayingState == RUNNING) { long currentTime = AnimationUtils.currentAnimationTimeMillis(); long currentPlayTime = currentTime - mStartTime; long timeLeft = mDuration - currentPlayTime; mStartTime = currentTime - timeLeft; mStartTimeCommitted = true; // do not allow start time to be compensated for jank mReversing = !mReversing; } else if (mStarted) { end(); } else { start(true); } }
public float getAnimatedFraction() { return mCurrentFraction; }
@Override public ValueAnimator clone() { final ValueAnimator anim = (ValueAnimator) super.clone(); if (mUpdateListeners != null) { anim.mUpdateListeners = new ArrayList(mUpdateListeners); } anim.mSeekFraction = -1; anim.mPlayingBackwards = false; anim.mReversing = false; anim.mCurrentIteration = 0; anim.mInitialized = false; anim.mPlayingState = STOPPED; anim.mStartedDelay = false; anim.mStarted = false; anim.mRunning = false; anim.mPaused = false; anim.mResumed = false; anim.mStartListenersCalled = false; anim.mStartTime = 0; anim.mStartTimeCommitted = false; anim.mPauseTime = 0; anim.mCurrentFraction = 0; anim.mDelayStartTime = 0; PropertyValuesHolder[] oldValues = mValues; if (oldValues != null) { int numValues = oldValues.length; anim.mValues = new PropertyValuesHolder[numValues]; anim.mValuesMap = new HashMap(numValues); for (int i = 0; i < numValues; ++i) { PropertyValuesHolder newValuesHolder = oldValues[i].clone(); anim.mValues[i] = newValuesHolder; anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder); } } return anim; }
RxJava(響應式編程) RxJava 在 GitHub 主頁上的自我介紹是 “a library for composing asynchronous a
一、為什麼Android要進行分辨率與屏幕適配最大的原因是碎片化,因為Android的開源措施和各個廠商的自己細微修改,結果就變成了這個樣需要適配的屏幕尺寸就有這麼多:這
本文總結分析了Android編程獲取控件寬和高的方法。分享給大家供大家參考,具體如下:我們都知道在onCreate()裡面獲取控件的高度是0,這是為什麼呢?我們來
預備知識 android手機的內部存儲設備分RAM和ROM,RAM是運行內存,掉電就會失去所有內容;ROM中的內容掉電後也不會丟失。 比如一台手機的規格