編輯:關於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;
}
Android----Rxjava與Retrofit初體驗
RxJava(響應式編程) RxJava 在 GitHub 主頁上的自我介紹是 “a library for composing asynchronous a
Android的分辨率和屏幕適配詳解
一、為什麼Android要進行分辨率與屏幕適配最大的原因是碎片化,因為Android的開源措施和各個廠商的自己細微修改,結果就變成了這個樣需要適配的屏幕尺寸就有這麼多:這
Android編程獲取控件寬和高的方法總結分析
本文總結分析了Android編程獲取控件寬和高的方法。分享給大家供大家參考,具體如下:我們都知道在onCreate()裡面獲取控件的高度是0,這是為什麼呢?我們來
Android Root原理和流程分析
預備知識 android手機的內部存儲設備分RAM和ROM,RAM是運行內存,掉電就會失去所有內容;ROM中的內容掉電後也不會丟失。 比如一台手機的規格