自定義View簡(jiǎn)介 - onMeasure,onDraw,自定義屬性

1. 概述


自定義View這東西很多哥們比較畏懼,如果你認(rèn)為他比較難,關(guān)鍵還是缺少實(shí)踐寫(xiě)得少;如果你認(rèn)為很簡(jiǎn)單,那可能是你沒(méi)有遇到過(guò)那些奇葩的效果,需要高等數(shù)學(xué)和各種算法。當(dāng)然我想要做的就是讓大家覺(jué)得很簡(jiǎn)單,如果你做了一兩年Android開(kāi)發(fā),給你一個(gè)效果根本沒(méi)法下手,會(huì)比較尷尬。自定義View是第一個(gè)坎,系統(tǒng)架構(gòu),數(shù)據(jù)結(jié)構(gòu)算法,內(nèi)存優(yōu)化,NDK后面還會(huì)有很多坎,每一個(gè)坎都需要花一定的時(shí)間。
  
  對(duì)于自定義View其實(shí)有一些套路,比如onMeasure(),onDarw(),onTouch(),自定義屬性,我們需要知道是用來(lái)干什么的,剩下就是一些邏輯代碼了,其實(shí)也很簡(jiǎn)單。當(dāng)然后面講自定義ViewGroup需要看源碼,后面的事后面再說(shuō),今天這里我們主講自定義View的一些基礎(chǔ)知識(shí)。

2. 自定義View方法簡(jiǎn)介


系統(tǒng)給我們提供了很多控件,比如TextView,ImageView,Button等等,這些其實(shí)也可以說(shuō)是自定義View,只不過(guò)這些是Google工程師已經(jīng)寫(xiě)好,提供給我們用的而已。

TextView

我們自己實(shí)現(xiàn)一個(gè)TextView的效果算做是入門(mén),這期主要介紹幾個(gè)方法,下期再寫(xiě)邏輯代碼:

  • onMeasure():用于測(cè)量,你的控件占多大的地方由這個(gè)方法指定;
  • onDarw():用于繪制,你的控件呈現(xiàn)給用戶(hù)長(zhǎng)什么樣子由這個(gè)方法決定;
  • onTouch():用于觸摸,處理與用戶(hù)交互,比如你手指拖動(dòng)應(yīng)該是什么效果由這個(gè)方法決定;
  • 自定義屬性:用于配置,布局中android:text="1"就顯示1,android:text="2"就是顯示2.

2.1. onMeasure()方法

對(duì)于onMeasure我們不得不說(shuō)一下測(cè)量模式,發(fā)現(xiàn)網(wǎng)上很多人寫(xiě)的文章有些許差異。當(dāng)然測(cè)量模式與父View有一定的關(guān)系,這里我們先不關(guān)注,如果目前實(shí)在不懂那需要記住,分別是UNSPECIFIED,EXACTLYAT_MOST。至于怎么獲取怎么用我們下期再說(shuō)。(后面會(huì)分析View的繪制流程源碼,會(huì)有些許差別)

        /**
         * Measure specification mode: The parent has not imposed any constraint
         * on the child. It can be whatever size it wants.
         */
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;

        /**
         * Measure specification mode: The parent has determined an exact size
         * for the child. The child is going to be given those bounds regardless
         * of how big it wants to be.
         */
        public static final int EXACTLY     = 1 << MODE_SHIFT;

        /**
         * Measure specification mode: The child can be as large as it wants up
         * to the specified size.
         */
        public static final int AT_MOST     = 2 << MODE_SHIFT;
  • UNSPECIFIED :任意大小,想要多大就多大,盡可能大,一般我們不會(huì)遇到,如ListView,RecyclerView,ScrollView測(cè)量子View的時(shí)候給的就是UNSPECIFIED ,一般開(kāi)發(fā)中不需要關(guān)注它;
  • EXACTLY :一個(gè)確定的值,比如在布局中你是這樣寫(xiě)的layout_width="100dp","match_parent","fill_parent";
  • AT_MOST:包裹內(nèi)容,比如在布局中你是這樣寫(xiě)的layout_width="wrap_content"。

ScrollView嵌套ListView會(huì)出現(xiàn)顯示不全的現(xiàn)象,怎么解決這個(gè)問(wèn)題的?網(wǎng)上很多解決方案copy就行,面試官問(wèn)你為什么會(huì)出現(xiàn)這現(xiàn)象為什么這么解決? 恩...GG。

2.2. onDarw()方法
  主要用來(lái)繪制效果,里面會(huì)有一個(gè)參數(shù)那就是canvas畫(huà)布,利用canvas就可以畫(huà)各式各樣的效果,如:canvas.drawCircle()畫(huà)圓形,canvas.drawBitmap()畫(huà)bitmap,我們這里肯定是需要畫(huà)文字,那就是drawText()畫(huà)文本。

    @Override
    protected void onDraw(Canvas canvas) {
        // 畫(huà)圓
        canvas.drawCircle();
        // 畫(huà)bitmap
        canvas.drawBitmap();
        // 畫(huà)文本
        canvas.drawText();
        // ......
    }

2.3. onTouch()方法

用來(lái)處理觸摸事件與用戶(hù)進(jìn)行交互,比如我早期寫(xiě)過(guò)QQ5.0,6.0側(cè)滑效果,字母索引列表效果等等。MotionEvent.ACTION_DOWN(手指按下)、MotionEvent.ACTION_MOVE(手指移動(dòng))、ACTION_UP(手指抬起)。當(dāng)然還有一個(gè)比較難以處理的,就是事件分發(fā)問(wèn)題,要看過(guò)源碼才行,后面再說(shuō)。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.e(TAG,"ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG,"ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Log.e(TAG,"ACTION_UP");
                break;
        }
        return super.onTouchEvent(event);
    }

2.3. 自定義屬性
  
  自定義屬性就是做到配置不寫(xiě)死,比如我在TextView中text配置什么就顯示什么,textColor指定什么顏色就顯示什么顏色等等,這些都是自定義屬性。首先在res下的values目錄下新建一個(gè)attrs.xml文件,其他名稱(chēng)可以嗎?是可以的如attr.xml或者lqbz.xml但是原則上一看attrs就知道是自定義屬性。

<resources>
    // 自定義TextView
    <declare-styleable name="TextView">
        // name 是名稱(chēng),format是格式  color(顏色),string(文本),dimension(sp,dp)...
        <attr name="textColor" format="color"/>
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
    </declare-styleable>
</resources>

在布局文件中使用

<com.darren.view.TextView
        // app: 自定義屬性
        app:text="自定義文本"
        app:textColor="@color/colorAccent"
        app:textSize="18sp"
        // android: 系統(tǒng)自帶的屬性
        android:layout_width="wrap_content"
        android:layout_height="match_parent" />

代碼中獲取,我們可以去仿照TextView的源碼寫(xiě)

    public TextView(Context context) {
        this(context,null);
    }

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

    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 獲取TypedArray
        TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.TextView);
        // 獲取文本
        mText = typedArray.getText(R.styleable.TextView_text);
        // 獲取文字顏色
        mTextColor = typedArray.getColorStateList(R.styleable.TextView_textColor);
        // 獲取文字大小
        mTextSize = typedArray.getDimensionPixelSize(R.styleable.TextView_textSize,mTextSize);
        // 回收
        typedArray.recycle();
    }

萬(wàn)丈高樓平地起,萬(wàn)事開(kāi)頭難。下期我們?cè)賮?lái)寫(xiě)邏輯代碼就算是入了門(mén),以后所有的自定義效果也離不開(kāi)這幾個(gè)方法,離不開(kāi)這些套路。

所有分享大綱:Android進(jìn)階之旅 - 自定義View篇

視頻講解地址:http://pan.baidu.com/s/1sllnOcd

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

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

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