自定View

157 阅读1分钟

绘制流程

自定义View需要经过流程measure,layout,draw,将View展示出来。 measure:测量view宽高 layout:确定子View的位置 draw:将View绘制到屏幕

为什么需要测量(onMeasure)?

xml布局中,wrap_content和match_parent只是对宽高的限制,并没有具体大小。所以需要测量确定大小,来自定View大小。

MeasureSpec封装了对View的布局要求。

MeasureSpec代表一个32位的int值,高2位表示SpecMode,低30位表示SpecSize

测量模式有三种:EXACTLY(固定尺寸),AT_MOST(当前View取得的最大尺寸),UNSPECIFIED(没有任何限制)

使用时mactch_parent对应EXACTLY,wrap_content对应AT_MOST

为什么需要布局(onLayout)?

对于自定义ViewGroup,需要通过重写onLayout方法来确定子View的位置。自定View可以不重写onLayout方法。

为什么要进行绘制(onDraw)?

绘制是在通过测量和布局后,在限制的范围内,绘制自己需要的图形。

自定义ViewGroup实例

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int childCount = getChildCount(); //获取子View数量
    //遍历子View,最子View自身进行测量
    for(int i = 0;i < childCount;i++){
        View childAt = getChildAt(i);
        measureChild(childAt,widthMeasureSpec,heightMeasureSpec);
    }

}
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    int width = 0;
    int height = 0;
    Log.d(TAG,"Befor l = "+l+" t = "+t+" r = "+r+" b = "+b);
    for(int i = 0;i < getChildCount();i++){
        View childView = getChildAt(i);
        width = childView.getMeasuredWidth();
        height = childView.getMeasuredHeight();
        MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
        switch (i){
            case 0:
                l = layoutParams.leftMargin;
                t = getHeight() - height - layoutParams.bottomMargin;
                break;
            case 1:
                l = getWidth() - width - layoutParams.leftMargin - layoutParams.rightMargin;
                t = getHeight() - height - layoutParams.bottomMargin;
                break;
        }
       r = l + width;
        b = height + t;
        Log.d(TAG,"after l = "+l+" t = "+t+" r = "+r+" b = "+b);
        childView.layout(l,t,r,b);
    }
}