Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

Android自定義view的定義

自定義 View 就是通過繼承 View 或者 View 的子類,並在新的類裡面實現相應的處理邏輯(重寫相應的方法),以達到自己想要的效果。

分類#

  • 自定義 ViewGroup:自定義 ViewGroup 一般是利用現有的組件根據特定的佈局方式來組成新的組件,大多繼承自 ViewGroup 或各種 Layout,包含有子 View。
  • 自定義 view: 在沒有現成的 View,需要自己實現的時候,就使用自定義 View,一般繼承自 View,SurfaceView 或其他的 View,不包含子 View。

構造函數#

無論是我們繼承系統 View 還是直接繼承 View,都需要對構造函數進行重寫,構造函數有多個,至少要重寫其中一個才行。

public class TestView extends View {
    /**
     * 在java代碼裡new的時候會用到
     * @param context
     */
    public TestView(Context context) {
        super(context);
    }

    /**
     * 在xml佈局文件中使用時自動調用
     * @param context
     */
    public TestView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 不會自動調用,如果有默認style時,在第二個構造函數中調用
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    /**
     * 只有在API版本>21時才會用到
     * 不會自動調用,如果有默認style時,在第二個構造函數中調用
     * @param context
     * @param attrs
     * @param defStyleAttr
     * @param defStyleRes
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public TestView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
}

繪制過程#

  • 測量
  • 佈局
  • 繪制
  • 提供接口

測量階段#

  • View 的父 View 通過調用 View 的 measure () 方法將父 View 對 View 尺寸要求傳進來。
  • View 的 measure () 方法進行一些前置和優化工作
  • 調用 onMeasure () 方法,在方法中根據業務需求進行相應的邏輯處理。在自定義 ViewGroup 的 onMeasure () 方法中,ViewGroup 會遞歸調用子 View 的 measure () 方法,並通過 measure () 將 ViewGroup 對子 View 的尺寸要求(對自己的尺寸要求和自己的可用空間計算出自己對子 View 的尺寸要求)傳入,對子 View 進行測量,並把測量結果臨時保存,以便在佈局階段使用。ViewGroup 會根據子 View 的實際尺寸計算出自己的期望尺寸,並通過 setMeasuredDimension () 方法告知父 View(ViewGroup 的父 View)自己的期望尺寸。
  • 方法裡調用 **setMeasuredDimension ()** 方法告知父 View 自己的期望尺寸

onMeasure () 計算 View 的期望尺寸的方法:

  • 參考父 View 的對 View 的尺寸要求和實際業務需求計算出 View 的期望尺寸:
    • 解析 widthMeasureSpec;
    • 解析 heightMeasureSpec;
    • 將「根據實際業務需求計算出 View 的尺寸」根據「父 View 的對 View 的尺寸要求」進行相應的修正得出 View 的期望尺寸(通過調用 resolveSize () 方法)
  • 通過 setMeasuredDimension () 保存 View 的期望尺寸(實際上是通過 setMeasuredDimension () 告知父 View 自己的期望尺寸

onMeasure() :

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthsize  MeasureSpec.getSize(widthMeasureSpec);      //取出寬度的確切數值
    int widthmode  MeasureSpec.getMode(widthMeasureSpec);      //取出寬度的測量模式
    
    int heightsize  MeasureSpec.getSize(heightMeasureSpec);    //取出高度的確切數值
    int heightmode  MeasureSpec.getMode(heightMeasureSpec);    //取出高度的測量模式
}

widthMeasureSpec 和 heightMeasureSpec 這兩個 int 類型的參數其實不是寬和高, 而是由寬、高和各自方向上對應的測量模式來合成的一個值

佈局階段#

  1. 父 View 通過調用 View 的 Layout 方法將 View 的實際尺寸傳給 View
  2. View 在 Layout 方法中調用 setFramne () 方法保存
  3. setFrame () 方法中又會調用 onSizeChanged () 方法告知開發者 View 的尺寸修改了
  4. View 的 Layout () 方法調用 View 的 onLayout () 方法,它是一個空實現。但是在 ViewGroup 中,這裡會調用子 View 的 Layout () 方法,將子 View 的實際尺寸傳給他們,讓子 View 保存實際尺寸。在自定義 ViewGroup 中需要重寫該方法。

繪制階段#

  • draw () ,總調度方法,會調用繪制背景的方法,繪制主題的方法,繪制前景的方法和繪制子 View 的方法
  • onDraw () ,繪制 View 主體內容的方法
  • dispatchDraw (),繪制子 View 的方法,在自定義 ViewGroup 中會調用 ViewGroup.drawChild () 方法,這個方法會調用每個子 View 的 View.draw ()
  • drawBackground (),繪制背景的方法,不可重寫,只能通過 xml 佈局文件或者 setBackground () 方法來設置背景。
  • onDrawForegound (),繪制 View 前景的方法,繪制主體內容之上的東西的時候在該方法中實現。

提供接口#

寫一些控制 View 或者監聽 View 某些狀態。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。