自定义View

  • View绘制流程 View的绘制基本由measure()、layout()、draw()这个三个函数完成
    测量: onMeasure(): 测量自己的大小,为正式布局提供建议 布局:
    onLayout(): 使用layout()函数对所有子控件布局 绘制:
    onDraw(): 根据布局的位置绘图
    不管是自定义View还是系统提供的TextView这些,它们都必须放置在LinearLayout等一些ViewGroup中,因此理论上我们可以很好的理解onMeasure(),onLayout(),onDraw()这三个函数:
    1.View本身大小多少,这由onMeasure()决定;
    2.View在ViewGroup中的位置如何,这由onLayout()决定;
    3.绘制View,onDraw()定义了如何绘制这个View。
    首先先了解几个需要用到的方法:
      (1)、setMeasuredDimension(width, height); 这个方法和onMeasure()方法类似。其实这个方法的作用就是 设置当前View的宽高。

(2)、 protected void Layout( int l, int t, int r, int b) {这个方法就和onLayout()方法类似了,不过少了第一个参数boolean changed这个方法的目的是用于当前ViewGroup中的子控件的布局

onMeasure

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

参数即父类传过来的两个宽高的"建议值",
即把当前view的高设置为:heightMeasureSpec ;
宽设置为:widthMeasureSpec
这个参数不是简单的整数类型,而是2位整数(模式类型)和30位整数(实际数值) 的组合
在onMeasure(int, int)中,必须调用setMeasuredDimension(int width, int height)
来存储测量得到的宽度和高度值,如果没有这么去做会触发异常IllegalStateException。
也可以调用父view的onMeasure(int, int)方法。

例子:重写OnMeasure()方法
    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
        int width;  
        int height;  
        if (widthMode == MeasureSpec.EXACTLY) {  
            // Parent has told us how big to be. So be it.  
            width = widthSize;  
        } else {  
            if (mLayout != null && mEllipsize == null) {  
                des = desired(mLayout);  
            }       ...  
        setMeasuredDimension(width, height);   

在ViewGroup中,给View分配的空间大小并不是确定的,有可能随着具体的变化而变化,而这个变化的条件就是传到specMode中决定的,specMode一共有三种可能:
MeasureSpec.EXACTLY:父视图希望子视图的大小应该是specSize中指定的。
MeasureSpec.AT_MOST:子视图的大小最多是specSize中指定的值,也就是说不建议子视图的大小超过specSize中给定的值。
MeasureSpec.UNSPECIFIED:我们可以随意指定视图的大小。
模式的值有:
wrap_content — MeasureSpec.AT_MOST–2
match_parent — MeasureSpec.EXACTLY-----1
具体值 — MeasureSpec.UNSPECIFIED---------0

注意:当模式是MeasureSpec.AT_MOST时,即wrap_content时,需要将大小设置一个数值。

onLayout()

onLayout方法是ViewGroup中子View的布局方法,用于放置子View的位置。放置子View很简单,只需在重写onLayout方法,然后获取子View的实例,调用子View的layout方法实现布局。在实际开发中,一般要配合onMeasure测量方法一起使用。

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int top = 0;
        int count = getChildCount();
        for (int i=0;i<count;i++) {
            View child = getChildAt(i);
            int childHeight = child.getMeasuredHeight();
            int childWidth = child.getMeasuredWidth();
            //该子控件在父容器的位置  , 高度是之前所有子控件的高度和开始 ,从上往下排列,就实现了类似Linearlayout布局垂直排列的布局
            child.layout(0, top, childWidth, top + childHeight); //以父容器左上角为原点进行布局
            top += childHeight;
        }
    }

该方法在ViewGroup中定义是抽象函数,继承该类必须实现onLayout方法,而ViewGroup的onMeasure并非必须重写的。View的放置都是根据一个矩形空间放置的,onLayout传下来的l,t,r,b分别是放置父控件的矩形可用空间(除去margin和padding的空间)的左上角的left、top以及右下角right、bottom值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值