編輯:關於Android編程
最近對android中的動畫特別感興趣,可能是因為比較喜歡跟UI相關的東西吧。這篇文章將簡單的介紹下ViewPropertyAnimator這個類的源碼和一些使用。
ViewPropertyAnimator這個類出現的原因應該是android為了方便我們在使用對於View對象的屬性動畫的時候而封裝的一個類,讓我們能夠更好的,更簡單的使用屬性動畫。在看文章之前,需要對屬性動畫有一定的了解,才能更好的弄明白這個類的作用的方便之處。還是推薦看郭神的博客。
我們都知道,在android中動畫可以分為這幾種,補間動畫,幀動畫,屬性動畫,當然了,現在可能還有的就是SVG矢量動畫,之後可能會寫關於矢量動畫的博客。先說前三種,優缺點什麼的,怎麼用什麼的。請自行百度。百度之後可以去看郭神的博客,有三篇關於屬性動畫的高級使用。這篇文章就是接著郭神沒說完的ViewPropertyAnimator來進行講解的。推薦大家以後做屬性動畫的時候都采用這種方式,真的是好用。
本人英文不是很好,對於android的理解也一般,如果有不對的地方,請不吝賜教。
先說下構造方法,因為這個類是專門用來處理View的屬性動畫的,所以它對象的創建必須跟View有關。
/**
* This method returns a ViewPropertyAnimator object, which can be used to animate
* specific properties on this View.
*
* @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
*/
public ViewPropertyAnimator animate() {
if (mAnimator == null) {
mAnimator = new ViewPropertyAnimator(this);
}
return mAnimator;
}`
我們可以通過view.animate()方法來獲得一個ViewPropertyAnimator對象,之後就可以使用ViewPropertyAnimator中的方法來實現我們想要的動畫。注意ViewPropertyAnimator中的方法返回值都是ViewPropertyAnimator對象,也就是說我們可以通過連綴的方式來實現對動畫的設置。
接下來讓我們來看下ViewPropertyAnimator這個類裡面都有什麼,先看屬性。
`
//關聯的view對象
private final View mView;
//動畫時長
private long mDuration;
//是否設置動畫時長
private boolean mDurationSet = false;
//動畫開始延遲
private long mStartDelay = 0;
//是否設置動畫開始延遲
private boolean mStartDelaySet = false;
//差值器
private TimeInterpolator mInterpolator;
//是否設置差值器
private boolean mInterpolatorSet = false;
//動畫監聽器
private Animator.AnimatorListener mListener = null;
//動畫監聽器(私有內部類,之後會講到)
private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
//NameValuesHolder的集合
ArrayList mPendingAnimations = new ArrayList();
//不同動作所執行的不同的任務類
private Runnable mPendingSetupAction;
private Runnable mPendingCleanupAction;
private Runnable mPendingOnStartAction;
private Runnable mPendingOnEndAction;
//View的常見屬性
private static final int NONE = 0x0000;
private static final int TRANSLATION_X = 0x0001;
private static final int TRANSLATION_Y = 0x0002;
private static final int SCALE_X = 0x0004;
private static final int SCALE_Y = 0x0008;
private static final int ROTATION = 0x0010;
private static final int ROTATION_X = 0x0020;
private static final int ROTATION_Y = 0x0040;
private static final int X = 0x0080;
private static final int Y = 0x0100;
private static final int ALPHA = 0x0200;
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
ROTATION | ROTATION_X | ROTATION_Y | X | Y;
//開啟動畫的任務
private Runnable mAnimationStarter = new Runnable() {
@Override
public void run() {
startAnimation();
}
};
/**
* This class holds information about the overall animation being run on the set of
* properties. The mask describes which properties are being animated and the
* values holder is the list of all property/value objects.
*這個類包含關於在集合中運行的全局動畫的信息。該掩碼描述了正在動畫中的屬性和值保持器是所有屬性/值對象的列表。
*百度翻譯。。。。。
*/
private static class PropertyBundle {
int mPropertyMask;
ArrayList mNameValuesHolder;
PropertyBundle(int propertyMask, ArrayList nameValuesHolder) {
mPropertyMask = propertyMask;
mNameValuesHolder = nameValuesHolder;
}
//是否成功取消動畫
boolean cancel(int propertyConstant) {
if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
int count = mNameValuesHolder.size();
for (int i = 0; i < count; ++i) {
NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
if (nameValuesHolder.mNameConstant == propertyConstant) {
mNameValuesHolder.remove(i);
mPropertyMask &= ~propertyConstant;
return true;
}
}
}
return false;
}
}
/**
* This list tracks the list of properties being animated by any particular animator.
* In most situations, there would only ever be one animator running at a time. But it is
* possible to request some properties to animate together, then while those properties
* are animating, to request some other properties to animate together. The way that
* works is by having this map associate the group of properties being animated with the
* animator handling the animation. On every update event for an Animator, we ask the
* map for the associated properties and set them accordingly.
*/
//這個大家自行翻譯吧,我怕我翻譯不好說錯了影響大家,表面上就是五個Map分別保存著PropertyBundle
//和不同的任務對象
private HashMap mAnimatorMap =
new HashMap();
private HashMap mAnimatorSetupMap;
private HashMap mAnimatorCleanupMap;
private HashMap mAnimatorOnStartMap;
private HashMap mAnimatorOnEndMap;
//這個類持有著我們想要更改的屬性和對應的值。可以這麼理解為比如alpha 0f,1f
private static class NameValuesHolder {
int mNameConstant;
float mFromValue;
float mDeltaValue;
NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
mNameConstant = nameConstant;
mFromValue = fromValue;
mDeltaValue = deltaValue;
}
}
/**
* Constructor, called by View. This is private by design, as the user should only
* get a ViewPropertyAnimator by calling View.animate().
*構造方法,被View調用,設計成私有的是為了使用者只能通過View.animate()方法調用來獲得一個ViewPropertyAnimator對象
* @param view The View associated with this ViewPropertyAnimator
*/
ViewPropertyAnimator(View view) {
mView = view;
view.ensureTransformationInfo();
}
`
好了,通過上面的代碼。我們對ViewPropertyAnimator這個類有了一個初步的認識,基本的屬性都有一個簡單的認識(哎,英文不好見諒),接下來我們來看看它都有哪些方法。
大家可以看到在圖片中有很多對View屬性進行設置的方法,而且方法的返回值都是ViewpropertyAnimator對象,這樣我能就可以使用連綴了。找其中一個看看。
public ViewPropertyAnimator alpha(float value) {
animateProperty(ALPHA, value);
return this;
}
可以看到其中執行了animateProperty這個方法,跟蹤過去看看。
/**
* Utility function, called by animateProperty() and animatePropertyBy(), which handles the
* details of adding a pending animation and posting the request to start the animation.
*
* @param constantName The specifier for the property being animated
* @param startValue The starting value of the property
* @param byValue The amount by which the property will change
*/
private void animatePropertyBy(int constantName, float startValue, float byValue) {
// First, cancel any existing animations on this property
if (mAnimatorMap.size() > 0) {
Animator animatorToCancel = null;
Set animatorSet = mAnimatorMap.keySet();
for (Animator runningAnim : animatorSet) {
PropertyBundle bundle = mAnimatorMap.get(runningAnim);
if (bundle.cancel(constantName)) {
// property was canceled - cancel the animation if it's now empty
// Note that it's safe to break out here because every new animation
// on a property will cancel a previous animation on that property, so
// there can only ever be one such animation running.
if (bundle.mPropertyMask == NONE) {
// the animation is no longer changing anything - cancel it
animatorToCancel = runningAnim;
break;
}
}
}
if (animatorToCancel != null) {
animatorToCancel.cancel();
}
}
NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
mPendingAnimations.add(nameValuePair);
mView.removeCallbacks(mAnimationStarter);
mView.post(mAnimationStarter);
}`
其中開始的部分是把之前在運行的動畫取消掉,然後把需要對view那個屬性進行修改和要修改的值封裝到nameValuePair中,添加到mPendingAnimations,最後調用View的Post方法在主線程中執行。而動畫的開始是在mAnimationStarter這個任務對象中的,可以看下之前的代碼就會發現其中調用了startAnimation()這個方法,我們來看看是怎麼執行的。
`
/**
* Starts the underlying Animator for a set of properties. We use a single animator that* simply runs from 0 to 1, and then use that fractional value to set each property
* value accordingly.
*/
private void startAnimation() {
mView.setHasTransientState(true);
ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
ArrayList nameValueList =
(ArrayList) mPendingAnimations.clone();
mPendingAnimations.clear();
int propertyMask = 0;
int propertyCount = nameValueList.size();
for (int i = 0; i < propertyCount; ++i) {
NameValuesHolder nameValuesHolder = nameValueList.get(i);
propertyMask |= nameValuesHolder.mNameConstant;
}
mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
if (mPendingSetupAction != null) {
mAnimatorSetupMap.put(animator, mPendingSetupAction);
mPendingSetupAction = null;
}
if (mPendingCleanupAction != null) {
mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
mPendingCleanupAction = null;
}
if (mPendingOnStartAction != null) {
mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
mPendingOnStartAction = null;
}
if (mPendingOnEndAction != null) {
mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
mPendingOnEndAction = null;
}
animator.addUpdateListener(mAnimatorEventListener);
animator.addListener(mAnimatorEventListener);
if (mStartDelaySet) {
animator.setStartDelay(mStartDelay);
}
if (mDurationSet) {
animator.setDuration(mDuration);
}
if (mInterpolatorSet) {
animator.setInterpolator(mInterpolator);
}
animator.start();
}`
可以看到其中對之前的屬性進行了判斷,如果不為null的話就添加到Map中進行統一的管理,最後加上監聽,設置常用屬性,這樣這個動畫就開始了。當然了,一個ViewPropertyAnimator肯定不止於此它還有許多能夠豐富動畫效果的方法比如withLayer,withStartAction,withEndAction等,不過我們日常需求所要用的方法上面你都有介紹了,而且這個動畫會自己啟動不需要我能去調用Start()方法來啟動動畫,當然也可以顯示的調用來執行,也支持去掉,同樣支持動畫的實時監聽。
textview.animate().x(500).y(500).setDuration(5000)
.setInterpolator(new BounceInterpolator());
常用的調用方式,直接點就可以,不需要更多的操作。
ViewPropertyAnimator這個類多與我們平時寫屬性的動畫真的幫助很大,而且更加方便使用,易於理解,,代碼看起來也更加的美觀。但它只是針對於view的,不是之前使用的valueAnimator那樣可以針對所有的對象,所以如果在之後的工作中如果想要更改View的屬性的話推薦用它,如果是其他的不是view的就需要使用ValueAnimator來實現控制。總體來說還是很好用的 ^_^.