Android開發之自定義View流程

Android控件架構

ViewGroup控件和View控件,ViewGroup控件作為父控件包含了多個View,并且管理著View控件,整個架構類似一個樹狀結構,上層負責控制著下層控件的繪制和測量,并且傳遞事件。
最頂部的是一個ViewParent對象,所有的交互事件都是由它統一控制和分配。

自定義View流程

View的測量>三種測量模式

  • EXACTLY(精確模式)
layout_width="100dip" 或者 layout_width="match_parent"
  • AT_MOST(最大模式)
    這種模式相當于自適應,子控件會隨著父控件的大小改變而改變,只要不超過父控件大小
  • UNSPECIFIED(不 指定其大小測量模式)

默認情況只支持EXACTLY模式

  • 如果是我們要使用warp_content,也需要重寫onMesure()方法。
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int specWidth;
    int specSize=MeasureSpec.getSize(widthMeasureSpec);
    int specMode=MeasureSpec.getMode(widthMeasureSpec);
    /精確模式 /
    if (specMode==MeasureSpec.EXACTLY){
    specWidth=specSize;
    }else {
    specWidth=200;
    /
    自適應模式
    /
    if (specMode==MeasureSpec.AT_MOST){
    specWidth=Math.min(specWidth,specSize);
    }
    }
    setMeasuredDimension(specWidth,specWidth);
    }

重寫后 我們可以發現
當我們設置寬度是為準確的値的時候會精確控件大小
當我們設置為match_parent屬性時,會填滿父控件
當我們設置warp_content時會使用 一個默認為200的默認值,如果不重寫onMesure()他會默認填充滿整個布局

View的繪制

   @Override
    protected void onDraw(Canvas canvas) {
        //在回調父類方法之前實現自己邏輯
        super.onDraw(canvas);
        //在實現父類方法之后實現自己的邏輯
        Canvas mcanvas=new Canvas(bitmap);
        mcanvas.drawBitmap(bitmap,0,0,null);
        Canvas mcanvas2=new Canvas(bitmap);
        mcanvas2.drawBitmap(bitmap,1,1,null);
    }

Canvas的繪制都發生在bitmap上面
所以上面的兩次繪制雖然是兩個Canvas對象,其實當你第二次繪制后,在刷新,
第一個一樣發生了變化。

自定義實現一個全代碼的ViwePager指示器

Paste_Image.png

Paste_Image.png
package com.project1;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/*
 * 創建人:Yangshao
 * 創建時間:2017/1/4 10:46
 * @version 一個Viewpager的指示器  多個圓點輪回選中效果
 *
 */
public class ViewPagerPointer extends View {

    private Context mContext;

    public ViewPagerPointer(Context context) {
        this(context, null);
        this.mContext = context;
    }

    public ViewPagerPointer(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ViewPagerPointer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    private Paint mRedPaint; //繪制紅色選中圓點
    private Paint mWhilePaint; //繪制背景圓點
    private float RADUIO = 8f; //設置圓角半徑
    private float PADDING = 24f; //點與點之間的水平間距
    private int mPointerSize;  //圓點個數
    private int mSelectPointer;  //當前選中的


    public void setPointerSize(int pointerSize) {
        mPointerSize = pointerSize;
    }

    public void setSelectPointer(int selectPointer) {
        mSelectPointer = selectPointer;
        invalidate();
    }

    /*測量設置寬高*/
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int specWidth, specHeight;
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthMode == MeasureSpec.EXACTLY) {
            specWidth = widthSize;
        } else {
            //一個圓點的寬度加上點與點之間的間距
            specWidth = dip2px(RADUIO * 2 + PADDING * (mPointerSize - 1));
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            specHeight = heightSize;
        } else {
            specHeight = dip2px(RADUIO * 2);
        }
        setMeasuredDimension(specWidth, specHeight);
    }

    private void initPaint() {
        mSelectPointer = 0; //設置默認選中值
        mRedPaint = new Paint();
        mRedPaint.setAntiAlias(true);
        mRedPaint.setColor(Color.RED);
        mRedPaint.setStyle(Paint.Style.FILL);

        mWhilePaint = new Paint();
        mWhilePaint.setAntiAlias(true);
        mWhilePaint.setColor(Color.BLACK);
        mWhilePaint.setStyle(Paint.Style.STROKE);
    }

    /**
     * dip轉換px
     */
    public int dip2px(float dip) {
        if (mContext != null) {
            final float scale = mContext.getResources().getDisplayMetrics().density;
            return (int) (dip * scale + 0.5f);
        }
        return -1;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < mPointerSize; i++) {
            if (i == mSelectPointer) {
                canvas.drawCircle(dip2px(RADUIO+i*PADDING), dip2px(RADUIO), dip2px(RADUIO), mRedPaint);
            } else {
                canvas.drawCircle(dip2px(RADUIO+i*PADDING), dip2px(RADUIO), dip2px(RADUIO), mWhilePaint);
            }
        }
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容