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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章