Android自定義View學習二---流程

Android自定義View學習二

參考:

自定義View繪製流程函數調用鏈(簡化版)

流程

構造函數

構造函數有四種重載:

//一般在直接New一個View的時候調用
public void SloopView(Context context) {}
//一般在layout文件中使用的時候會調用,關於它的所有屬性(包括自定義屬性)都會包含在attrs中傳遞進來
public void SloopView(Context context, AttributeSet attrs) {}

public void SloopView(Context context, AttributeSet attrs, int defStyleAttr) {}
public void SloopView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {}

onMeasure方法

onMeasure(int widthMeasureSpec, int heightMeasureSpec)

Called to determine the size requirements for this view and all of its children
調用此方法來決定view和其子view的size

  • widthMeasureSpecheightMeasureSpec其實不是寬和高,而是由寬、高和各自方向上對應的模式來合成的一個值:其中,在int類型的32位二進制位中,31-30這兩位表示模式,0~29這三十位表示寬和高的實際值
  • 模式有三種
    • UNSPECIFIED
    • EXACTLY
    • AT_MOST

參考:onMeasure custom view explanation

  • EXACTLY - 表示layout_width或者layout_height被設置成一個指定的值。
  • AT_MOST - typically means the layout_width or layout_height value was set to match_parent or wrap_content where a maximum size is needed (this is layout dependent in the framework), and the size of the parent dimension is the value. You should not be any larger than this size.
    表示layout_width或者layout_height被設置爲match_parent或者wrap_content,指定的是最大值,不應該大於這個值
  • UNSPECIFIED - 默認值,父控件沒有給子view任何限制,子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);    //取出高度的測量模式
}

約定:在重寫onMeasure方法時,必須調用setMeasuredDimension(int, int)方法來存儲view的measured的寬度和高度。如果沒有這麼做,將會由measure(int, int)方法拋出一個IllegalStateException

覆寫onMeasure方法的時候,子類有責任確保measured height and width至少爲這個View的最小height和width。(getSuggestedMinimumHeight()getSuggestedMinimumWidth()

Custom View: mastering onMeasure一文中,提到在實現onMeasure方法是,要注意到如下的幾點:

  • The padding
  • The minimum width and minimum height of our view (use getSuggestedMinimumWidth() and getSuggestedMinimumHeight() to get those values)
  • The widthMeasureSpec and heightMeasureSpec which are the requirements passed to us by the parent

其實現如下:

private int measureDimension(int desiredSize, int measureSpec) {
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = desiredSize;
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }

        if (result < desiredSize){
            Log.e("ChartView", "The view is too small, the content might get cut");
        }
        return result;
    }

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.v("Chart onMeasure w", MeasureSpec.toString(widthMeasureSpec));
        Log.v("Chart onMeasure h", MeasureSpec.toString(heightMeasureSpec));

        int desiredWidth = getSuggestedMinimumWidth() + getPaddingLeft() + getPaddingRight();
        int desiredHeight = getSuggestedMinimumHeight() + getPaddingTop() + getPaddingBottom();

        setMeasuredDimension(measureDimension(desiredWidth, widthMeasureSpec),
                measureDimension(desiredHeight, heightMeasureSpec));
    }

onSizeChanged

onSizeChanged方法確定view的大小,可以獲取到view的寬和高

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章