自定義 View 實踐(一)- 自定義圓點視圖


這篇文章是基于以下兩篇文章的實踐:
1.自定義View - 基礎(chǔ)
2.自定義View - Canvas - 圖形繪制


我們在常用的 UI 布局中,常會用到這樣的圓點:


效果圖-g.png

當(dāng)然我們可以用一張圖片,利用 tintMode 顯示出不同的顏色,從而實現(xiàn)這樣的效果,這一點,我在之前 Material Design 中已經(jīng)講過。

今天,我們利用自定義 View 來實現(xiàn)。

一、第一步:考慮需要的屬性

對于這個圓點,在項目需求中,通常只是一個指示器,因此需要設(shè)置的屬性并不多。大致有兩個:

  • 顏色
  • 大小 ,這里我們將大小參數(shù)定為半徑

設(shè)定的屬性需要寫在 styles.xml 中(為了區(qū)分,你也可以新建一個 xml 文件用于存儲自定義 View 的屬性聲明)

    <declare-styleable name="PointView">
        <attr name="radio" format="dimension"></attr>
        <attr name="pointColor" format="color"></attr>
    </declare-styleable>

說明:

  • 聲明屬性要用 declare-styleable 標(biāo)簽包裹,其中 name 屬性為 新建類的類名。
  • attr 中為各個屬性的說明,包括名稱(name),類型(format)

二、第二步:新建類,并獲取屬性

這里我自定義的 View 為 PointView。首先繼承 View 并重寫構(gòu)造器。在構(gòu)造器中,我們需要初始化畫筆,并獲取 xml 中自定義的屬性。

public class PointView extends View {

    private float mRadio = 3;
    private int mPointColor = Color.BLACK;
    private Paint mPaint;

    public PointView(Context context) {
        super(context);
        initPaint();
    }

    public PointView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = null;
        try {
            ta = context.obtainStyledAttributes(attrs, R.styleable.PointView);
            mRadio = ta.getDimension(R.styleable.PointView_radio, dp2px(3));
            mPointColor = ta.getColor(R.styleable.PointView_pointColor, Color.YELLOW);
        } finally {
            if (ta != null) {
                ta.recycle();
            }
        }
        initPaint();
    }

    private void initPaint(){
        if (mPaint == null) {
            mPaint = new Paint();
            mPaint.setColor(mPointColor);
            mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        }
    }
}

三、第三步:繪制圖形

這里的圓點圖形比較簡單,根據(jù)設(shè)置的半徑 mRadio 直接繪制圓形

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(mRadio,mRadio,mRadio,mPaint);
    }

四、第四步:測量視圖

我們需要重寫 onMeasure 方法,在這里根據(jù) Mode 獲取 width 和 height 的準(zhǔn)確值,并通過 setMeasuredDimension( resultWidth,resultHeight ) 使測量值生效。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int resultWidth = 0;
        int resultHeight = 0;
        int specWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        int specHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        int specHeightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (specWidthMode == MeasureSpec.AT_MOST) {//wrap_content
            resultWidth = (int) (mRadio * 2);
        }else{//match_parent
            resultWidth = specWidthSize;
        }

        if (specHeightMode == MeasureSpec.AT_MOST) {//wrap_content
            resultHeight = (int) (mRadio * 2);
        }else{//match_parent
            resultHeight = specHeightSize;
        }

        setMeasuredDimension(resultWidth,resultHeight);
    }

五、暴露部分方法

PointView 有兩個屬性:顏色和大小。上面的代碼只能保證在布局文件中聲明的 PointView 顯示正常,而代碼中初始化的 PointView 需要我們暴露出設(shè)置顏色和大小的 set 方法。

這里的 set 方法除了像普通實體類做了賦值操作之外,還必須調(diào)用 invalidate 方法,通知視圖重新繪制,否則屬性的變化并不能真正體現(xiàn)在視圖上。

    public void setColor(int color){
        initPaint();
        mPaint.setColor(color);
        invalidate();
    }

    public void setRadio(int radio){
        if (radio > 0) {
            mRadio = dp2px(radio);
        }
        requestLayout();
    }

結(jié)束語:其實項目里許多簡單的小東西可以通過代碼實現(xiàn),比如返回的小箭頭、關(guān)閉彈窗的 X 等等。也許現(xiàn)在還不能做出什么大東西,但是小玩意兒也會讓人覺得很有成就感啊。

謝謝觀賞
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容