自定义View、ViewGroup(温习&实战&笔记)

自定义View、ViewGroup的最基本的支持要点

  • 自定义View - onMeasure、onDraw

  1. wrap_content;

  2. padding;
  • 自定义ViewGroup - onMeasure、onLayout
  1. wrap_content;
  2. padding;
  3. margin;

为啥View只需支持padding,而ViewGroup需要支持padding和margin?

这里注意了,margin属于父子View之间的布局关系,是用于父容器计算内部子View的显示位置(onLayout)的,为啥padding不需要父容器干涉?padding是View内部需要支持的属性,不属于父子View之间的布局关系。

                              

  • 红色框线 - 父容器
  • 蓝色框线 - 子View的显示区域
  • 绿色框线 - 子View的绘制区域
  • A、B、C、D -  paddingTop、paddingLeft、paddingRight 、paddingBottom
  • E - 子View的绘制区域
  • 1、2、3、4 - marginTop、marginLeft、marginBottom、marginRight

其中,子View的显示区域 = 子View的绘制区域 (E)+ Padding(A、B、C、D),这才是子View实际的地盘。

而margin是父容器的地盘,有一句话叫各扫门前雪,所以子View处理好自己的Padding就好了。ViewGroup也是一个View(ps:可以包括子View的容器View),因此需要处理Padding,又因为它是一个容器,需要计算子View(在父容器中)的显示位置,这就需要将margin考虑在内了,因此必须处理margin。

父View的大小 = 子View大小总和 + 父View的padding总和 + 子View的margin总和;

那么wrap_content为啥也要处理?后面说。

自定义View

自定义一个View,只需处理测量(onMeasure)和重绘(onDraw)即可。

可以发现自定义View和自定义ViewGroup需要重写的方法是不同的,除了都需要重写onMeasure之外:

  • 自定义View只需额外重写onDraw即可
  • 自定义ViewGroup只需额外重写onLayout即可

于是就有了下面的对话:

父容器:你们(Views)在lz的地盘摆摊,摊位的位置老子定(onLayout),你们说了不算;

子View:好的,这个摊位咋个摆放货品,lz说的算(onDraw),你(父容器)管不着了;

父容器:好啊,但是这个摊位面积问题,咱俩得商量一下撒?不然我咋个知道!lz定完了(onLayout),会告诉你们。之后lz就不管了!

子View:可以啊,听起来你(父容器)很叼的样子!

其实,说白了,还是地盘问题~

看过View源码的同学都知道,View的onLayout是空实现,为啥呢?因为View不是容器,所以没有子View,自然onLayout是需要实现的。那么一个View到底要绘制到屏幕的位置呢?不用我们管么?确实,一般这块是不需要我们处理的。View的layout方法已经为我们实现好了。

    public void layout(int l, int t, int r, int b) {
	......

    // 关键方法:setOpticalFrame 、 setFrame
        boolean changed = isLayoutModeOptical(mParent) ?
                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
	......
 
    }

 至于onLayout的四个参数,表示View在屏幕中的位置(左上右下),这四个参数的值是父容器的事情,由父容器计算子View该在屏幕的哪个位置显示,计算完成然后告诉子View(childView.layout(l,t,r,b)),然后子View就乖乖的在这个区域进行onDraw了。

  • onMeasure

注意:此处可以解答为啥要支持wrap_content

-----------View的onMeasure处理逻辑----------
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

正常情况下,如果我们自定义View或者ViewGroup不重写onMeasure方法的话,则会调用View的onMeasure方法。注意,在View或者ViewGroup中,测量完成都是通过setMeasuredDimension保存宽高尺寸的。

可以看到,在默认的处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值