Android實現帶動畫效果的自定義View


 

准備工作:

考慮這個自定義view需要什么屬性來方便在xml布局里面改。

在values/attrs.xml里面添加自定義屬性,分別是尺寸,顏色,變大的倍數。

 

    <span style="font-size:14px;"><resources>
        <declare-styleable name="CustomView">
            <attr name="size" format="dimension" />
            <attr name="color" format="color" />
            <attr name="maxValue" format="float"/>
        </declare-styleable>
    </resources></span>

format是定義的屬性的類型,配置完成后,就可以在xml布局中使用這些屬性了。

繼承view之后,會有三個構造方法

    <span style="font-size:14px;">public class CustomView extends View{
     
        private int DEFAULT_SIZE = 100;//默認半徑
        private int DEFAULT_COLOR = Color.GREEN;//默認顏色
        private float DEFAULT_MAXVALUE = 1.6f;//默認放大倍數
     
        private int mSize;//半徑
        private int mColor;
        private Paint mPaint;
        private int mHeight;
        private int mWidth;
        private Float value = 1f;
        private Float maxValue;//實際放大的倍數
     
        private ValueAnimator anim;
     
        public CustomView(Context context) {
            super(context);
        }
     
        public CustomView(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray typedArray = context.getTheme().obtainStyledAttributes(
                    attrs,R.styleable.CustomView,0,0);
            mSize = typedArray.getDimensionPixelSize(R.styleable.CustomView_size,DEFAULT_SIZE);
            mColor = typedArray.getColor(R.styleable.CustomView_color,DEFAULT_COLOR);
            maxValue = typedArray.getFloat(R.styleable.CustomView_maxValue,DEFAULT_MAXVALUE);
     
            typedArray.recycle();
        }
     
        public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }</span>

第一個構造方法是在代碼中創建view,

<span style="font-size:14px;"> CustomView view = new CustomView(this);</span>

第二個是我們常用的構造方法,給每個自定義屬性設置個默認值,可以再布局中配置這些自定義屬性。這些屬性存放在第二個參數中。

第三個是需要指定style是調用。


然后開始自定義View。。。

主要會涉及三個方法,分別是onDraw(),onLayout(),onMeasure()。

1、onDraw():

      就是把要顯示的view畫出來,就是一個圓,很簡單。

    <span style="font-size:14px;">@Override
        protected void onDraw(Canvas canvas) {
            mPaint = new Paint();
            mPaint.setColor(mColor);
            mPaint.setAntiAlias(true);//抗鋸齒效果
            //畫圓,前兩個參數確定圓心,第三個參數是半徑
            canvas.drawCircle(mWidth/2,mHeight/2,mSize *value,mPaint);
        }</span>


2,、onLayout():

這個方法主要是確定當前view在父視圖中的位置

    @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            // 重設圓半徑,防止超出視圖大小
            mHeight = getMeasuredHeight();
            mWidth = getMeasuredWidth();
            int maxSize = (int) Math.min(mHeight/(2 * maxValue),mWidth/(2 * maxValue));
            mSize = mSize > maxSize ? maxSize : mSize;
        }

我在這里重寫這個方法是為了防止圓變大時,超出屏幕范圍。其中maxSize是view可以有的最大半徑,要考慮到圓變大時也不能超出屏幕,所以是mHeight / (2 * maxValue)。

其實沒必要重寫onLayout(),這里只是為了防止半徑設置的過大。。

在這里重寫onLayout()后,有個弊端,就是當在布局中寬高設置固定大小時,顯示的圓的半徑是所設置寬高的一半,例如寬高都

設置為20dp,所顯示的半徑為10dp。設置成wrap_content或者match_parent或者不重寫onLayout()就沒影響了。


3、onMeasure():

先提一句:onMeasure()方法不是每個自定義view都需要重寫的。下面簡單的了解一下onMeasure的用法。

在xml布局中,我們會設置wrap_content或者match_parent。

但是系統給我們測量得到的寬度和高度都是match_parent。

當我們用到wrap_content時,需要的是實際寬度或高度,而不是系統測量得到的match_parent,就需要我們自己測量,即重寫

onMeasure();這里的自定義view就不需要重寫onMeasure(),因為這里所需要的寬高就是match_parent,我們只是通

過寬高得到中心點畫圓即可。


4.view花完了,開始動畫部分,使用ValueAnimator實現的。

    public void startAnimation(){
            anim = ValueAnimator.ofFloat(value,maxValue);
            anim.setRepeatCount(ValueAnimator.INFINITE);//設置無限重復
            anim.setRepeatMode(ValueAnimator.REVERSE);//設置重復模式
            anim.setDuration(500);
            anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    value = (Float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
     
            anim.start();
        }


anim = ValueAnimator.ofFloat(value,maxValue);

得到ValueAnimator對象,其中兩個參數代表從value到maxValue平滑變化。

在監聽方法中,通過調用getAnimateValue()方法獲取動畫在播放過程中屬性值的變化,也就是上面參數變化過程中的一系列值。

通過postInvalidate()實現刷新,在onDraw()方法中

<span style="font-size:14px;">canvas.drawCircle(mWidth/2,mHeight/2,mSize *value,mPaint);</span>

半徑 = mSize * value,半徑不斷變化,實現了圓放大過程。

想要實現復雜的動畫可以了解了解ValueAnimator和ObjectAnimator。


最后在Activity中啟動動畫和關閉動畫

    public class MainActivity extends AppCompatActivity {
        private CustomView customView;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
     
            customView = (CustomView) findViewById(R.id.custom_view);
            customView.startAnimation();
            
            //customView.endAnimation();
        }
    }

Demo下載地址

---------------------
作者:蜉蝣DG
來源:CSDN
原文:https://blog.csdn.net/qy1993qy/article/details/52824888
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM