Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android屬性動畫--補充說明&進階

Android屬性動畫--補充說明&進階

編輯:關於Android編程

轉載請注明出處,謝謝~~
目錄

本文概述 動畫補充說明 屬性動畫的View加載方式 TypeEvaluator的使用 TimeInterpolator LayoutTransition Others 結束語

本文概述

上一篇博客我們講解了Android屬性動畫的一些基礎使用,主要是使用屬性動畫的幾種加載方式,有ObjectAnimator方式,ValueAnimator方式,AnimatorSet方式以及AnimatorInflater方式。這篇博客我們將繼續介紹一下Android一些其他執行屬性動畫的方式,和一些需要注意的點,本文可以看做是對上一篇的一個補充說明,也可以當做是對屬性動畫使用的進階。
這篇文章將要說明以下幾個問題:

View.animate() TypeEvaluator TimeInterpolator LayoutTransition others

動畫補充說明

屬性動畫的View加載方式

在Android API 12之後,View增加了一個方法,View.animate(),使用這個方法,就可以直接對這個view執行屬性動畫,我們看下代碼:

@SuppressLint("NewApi")
    private void findView() {
        tv_rotate = (TextView) findViewById(R.id.tv_rotate);
        iv_view = (ImageView) findViewById(R.id.iv_view);

        tv_rotate.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //API 12 
                iv_view.animate()
                        .rotationX(180.f)
                        .alpha(0.5f)
                        .scaleX(0.5f)
                        .scaleY(0.5f)
                        .setDuration(2000)
                        .setInterpolator(new LinearInterpolator())
                        .setListener(new /*API 11*/AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationStart(Animator animation) {}
                            @Override
                            public void onAnimationRepeat(Animator animation) {}

                            @Override
                            public void onAnimationEnd(Animator animation) {
                                Log.e(TAG, "animation end");
                                // API 11
                                iv_view.setAlpha(1.0f);
                                iv_view.setRotationX(0.f);
                            }

                            @Override
                            public void onAnimationCancel(Animator animation) {
                                onAnimationEnd(animation);
                            }
                        })
                        //API 16
                        .withStartAction(new Runnable() {
                            @Override
                            public void run() {
                                Log.e(TAG, "with start action");
                            }
                        })
                        //API 16
                        .withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                Log.e(TAG, "with end action");
                                //API 11
                                iv_view.setScaleX(1.0f);
                                iv_view.setScaleY(1.f);
                            }
                        })
                        .start();
//                      .setStartDelay(5000)//設置延遲時間
                }
        });
    }

在代碼裡,需要的API等級我都標示的很清楚,有一些方法甚至是在API16中才加入的。我們看下效果:
這裡寫圖片描述

然後看下我們打的log是不是執行了

03-24 22:35:24.737: E/View.animate(964): with start action
03-24 22:35:26.757: E/View.animate(964): animation end
03-24 22:35:26.757: E/View.animate(964): with end action

可以看到我們的log都執行了,設置了這些屬性之後我麼就可以在動畫執行前或是執行後做一些操作了。

TypeEvaluator的使用

Evaluator是求值器,評估器,也有人叫他估值器,是計算一定變化范圍內,某一個時段的一個值,這個值在變化兩端之間(包含首尾)。我們接下來舉幾個例子,從最簡單的開始:

public static void startValue2(final View view){
        ValueAnimator anim = new ValueAnimator();
        anim.setDuration(1000);
        anim.setObjectValues(0.0f,360.0f);
        anim.setEvaluator(new FloatEvaluator());
        anim.start();
        anim.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                view.setRotationX((Float)animation.getAnimatedValue());
            }
        });
    }

這是通過ValueAnimator使用估值器的一個例子。效果很簡單,也是以前實現的一個效果,只是實現的方式不同:
這裡寫圖片描述

使用估值器的例子還可以看我以前的一個自定義控件,它是單獨的把估值器抽出去,然後用估值器的值來設置一些屬性的變化,有點類似屬性動畫的思想。傳送門–自定義控件之背景變換

還有一種估值器是自定義估值器,這種方式說起來也不算復雜,只是你自己根據需求定義一個估值器來改變你想改變的屬性

public static void startValue(final View view){

        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setDuration(2000);
        valueAnimator.setObjectValues(new PointF(0, 0));
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setEvaluator(new TypeEvaluator(){
            // fraction = t / duration  取值范圍0-1,就是0-2000取值包含頭尾除以2000.
            @Override
            public PointF evaluate(float fraction, PointF startValue,PointF endValue){
                PointF point = new PointF();
                point.x = 200 * fraction * 3;
                point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
                return point;
            }
        });

        valueAnimator.start();
        valueAnimator.addUpdateListener(new AnimatorUpdateListener(){
            @Override
            public void onAnimationUpdate(ValueAnimator animation){
                PointF point = (PointF) animation.getAnimatedValue();
                view.setX(point.x);
                view.setY(point.y);
            }
        });
    }

這段代碼是我從別人那要的,非原創,嘿嘿,懶得寫這塊了,因為沒有合適的需求。效果圖我就不上了,這塊只談如何使用吧。

TimeInterpolator

這是時間插值器,怎麼理解呢?就是你的動畫的變化規則與速率,例如前邊代碼裡見過的LinearInterpolator,這是線性插值器,也就是你的動畫的變化是勻速的,就像你做一個位移動畫,前後位移的速度都一樣,是勻速運動,而如果你設置了AccelerateInterpolator,這就是加速插值器,你的位移就是加速的,非勻速運動。Android給提供了一些插值器,個人認為,完全夠用了。對於這些插值器你可能不是太了解,本文就做一個一一對應。

AccelerateDecelerateInterpolator:
這裡寫圖片描述

AccelerateInterpolator:
這裡寫圖片描述

AnticipateInterpolator:
這裡寫圖片描述

AnticipateOvershootInterpolator:
這裡寫圖片描述

BounceInterpolator:
這裡寫圖片描述

CycleInterpolatZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcqO6PGJyIC8+DQo8aW1nIGFsdD0="這裡寫圖片描述" src="/uploadfile/Collfiles/20150326/20150326084412160.png" title="\" />

DecelerateInterpolator:
這裡寫圖片描述

LinearInterpolator:
這裡寫圖片描述

OvershootInterpolator:
這裡寫圖片描述

這些圖都是來自網絡的搜集,有些只是描述了一個大致的走向,我麼可以根據走向選擇我們需要的插值器。

LayoutTransition

這個是對界面布局的一些操作,我們看看代碼:

/**
     * 根據傳遞過來的動畫類型返回相應的動畫,或者返回自定義動畫
     * @param transition
     * @param anim
     * @param type
     * @return
     */
    @SuppressLint("NewApi")
    public static Animator getTransition(LayoutTransition transition ,Animator anim , int type){
        Animator animator = null;
        if (anim == null) {
            if (type == LayoutTransition.APPEARING) {
                animator = transition.getAnimator(LayoutTransition.APPEARING);
            }else if (type == LayoutTransition.CHANGE_APPEARING) {
                animator = transition.getAnimator(LayoutTransition.CHANGE_APPEARING);
            }else if (type == LayoutTransition.DISAPPEARING) {
                animator = transition.getAnimator(LayoutTransition.DISAPPEARING);
            }else if (type == LayoutTransition.CHANGE_DISAPPEARING) {
                animator = transition.getAnimator(LayoutTransition.CHANGE_DISAPPEARING);
            }else {
                animator = transition.getAnimator(LayoutTransition.CHANGING);
            }
        }else{
            animator = anim;
        }
        return animator;
    }

我們看幾個屬性:
- LayoutTransition.APPEARING - view出現時,view本身的動畫
- LayoutTransition.CHANGE_APPEARING - view出現時,其他view的動畫(如果對其他view的布局有影響的話)
- LayoutTransition.DISAPPEARING - view消失時,view本身的動畫
- LayoutTransition.CHANGE_DISAPPEARING - view消失時,其他view的動畫(如果對其他view的布局有影響的話)

更加具體是使用去看代碼裡的調用吧,寫的都很明白。這些動畫可以用默認的,也可以完全自定義。

這裡寫圖片描述

Others

1.前邊說過了,屬性動畫是根據view的一些屬性來執行動畫,那麼它要改變這些屬性,必須要有對應的方法,例如改變背景,要有setBackgroundColor方法,我麼就可以對backgroundColor執行動畫。那麼如果碰到了沒有set方法的,怎麼辦,或者set方法不是改變對應屬性而是設置最大最小值(典型的button),我們來看看這樣的情況該怎麼解決。

第一種方式,定義Wrapper,裝飾我們要控制的view。

public class ViewWrapper {  
        private View mView;  

        public ViewWrapper(View view) {  
            mView = view;  
        }  

        public int getWidth() {  
            return mView.getLayoutParams().width;  
        }  

        public void setWidth(int width) {  
            mView.getLayoutParams().width = width;  
            mView.requestLayout();  
        }  

        public View getView(){
            return mView;
        }
    }

我們重寫下這個view的get和set方法,這樣就完成了對該屬性的改變。
看下效果:
這裡寫圖片描述

第二種方式,監聽器改變任意屬性。

/**
     * 通過ValueAnimator和一個估值器來改變button的寬度。由於button的setWidth不是設置當前寬度,而是設置最小和最大寬度(繼承自TextView),所以我們要
     * 用view.getLayoutParams().width方式來改變寬度,然後強制重繪界面。
     * @param view
     * @param start
     * @param end
     */
    @SuppressLint("NewApi")
    public static void changeWidthByValue(final View view,final int start, final int end){
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);

        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

            private IntEvaluator mEvaluator = new IntEvaluator();

            @Override
            public void onAnimationUpdate(ValueAnimator animator) {

                float currentValue = (Float)animator.getAnimatedValue();
                view.getLayoutParams().width = mEvaluator.evaluate(currentValue, start, end);
                view.requestLayout();
            }
        });

        valueAnimator.setDuration(2000).start();
    }

這是通過監聽器來改變button對應是屬性,其中也加入了估值器,這種方式與上一種方式實現的效果相同,但實現方式不同,最終思想確實統一的,看下效果:
這裡寫圖片描述

【注意】
在上面不知道你有沒有注意到,我們不管用哪種方式,都調用了requestLayout()方法,這是因為我們需要通過重繪界面(重測)來實現對屬性值的改變。在一些不會自己更新的屬性裡,我們都需要調用強制重繪方法來實現對屬性的改變,這也是自定義空間中經常用到的方式。

2.對動畫執行結束後的一些操作——監聽器

有時候我們執行動畫,需要在執行後讓view消失掉,這就需要對動畫執行後的一些監聽,前邊都用到了一些監聽器,現在再說兩種。

/**
     * 通過一個包裝類來實現對button的改變,set方法裡需要重繪界面,動畫執行完畢後可以讓view消失掉
     * @param view
     * @param from
     * @param to
     */
    public static void startAnim(final ViewWrapper view,int from , int to , boolean isDisappear){
        ObjectAnimator animator = ObjectAnimator.ofInt(view, "width", from, to);
        animator.setDuration(2000);

        if (isDisappear) {
            animator.addListener(new AnimatorListener() {

                @Override
                public void onAnimationStart(Animator animation) {
                    // do nothing
                }

                @Override
                public void onAnimationRepeat(Animator animation) {
                    // do nothing
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    ViewGroup parent = (ViewGroup) view.getView().getParent();
                    if (parent != null)
                        parent.removeView(view.getView());
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                    onAnimationEnd(animation);
                }
            });
        }

        animator.start();
    }

動畫執行完,讓它消失,看下效果:
這裡寫圖片描述

然後我們發現,這個監聽器需要復寫的方法也太多了,有沒有類似我們學適配器的時候,那種可以少寫幾個方法,或者自己選擇想復寫哪個的監聽器呢?答案是肯定的:

/**
     * 動畫執行完畢後可以讓view消失掉,使用一個較為簡單的監聽器
     * @param view
     * @param from
     * @param to
     */
    public static void startAnimAndDisappear(final View view,float from , float to){
        ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", from, to);
        animator.setDuration(2000);

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                ViewGroup parent = (ViewGroup) view.getParent();
                if (parent != null) {
                    parent.removeView(view);
                }
            }
        });

        animator.start();
    }

這個監聽器就自由的多了,我們可以根據需求選擇復寫哪個方法。同樣看下效果:
這裡寫圖片描述

結束語

關於Android屬性動畫的介紹就告一段落了,感覺使用上應該說的很詳細,至於更多的擴展,只有讀者自己慢慢發掘了,多想,多試驗,總能做出好東西來的。大家一起加油~!

Demo下載地址

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved