Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ViewPropertyAnimator源碼分析

ViewPropertyAnimator源碼分析

編輯:關於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來實現控制。總體來說還是很好用的 ^_^.

  1. 上一頁:
  2. 下一頁: