Android关于自定义ViewGroup,onMeasure的一些实验结论。

Android关于自定义ViewGroup,onMeasure的一些实验结论。

下文仅代表个人想法,如有错误,欢迎指正,不胜感激。

我们在写android程序的过程中,通常都是使用自带的控件,亦或者从网上查找别人写好的控件,但是用控件容易,写控件难,抱着求知的态度,自定义了一个ViewGroup(很简单)。现在说下在自定义ViewGroup过程中遇到的问题。

  • 自定义ViewGroup的过程
  • onMeasure方法
  • measureChildren方法
  • onLayout方法

关于上面四点的描述较为繁琐,只是为了我这样的小白能更深刻的理解。
直接看问题总结,请移步这里


自定义ViewGroup的过程

首先来说一下自定义View。让我们从机器的角度出发,要想在一个屏幕上绘制一个控件(以矩形图形为例),我们需要什么必要的参数?没错,是长和宽。只有获得长和宽,我们才能知道控件的大小。那么系统如何获得控件的大小的,onMeasure方法就是完成这件事的。然后再说自定义ViewGroup,ViewGroup内部有很多子View,它不仅需要知道自身的大小,还需要为子View安排位置,比如说我需要让一个Button显示的底部,这时候就需要onLayout方法来为子View设置位置。好,现在让我们想一下,在我们写xml的时候,我们其实有写过控件的大小,比如 android:layout_width=”150dp” android:layout_height=”150dp”。既然我们有了

onMeasure

首先说一下onMeasure实际上会被measure方法调用。

onMeasure,是用来测量自身的方法,这个听起来会感觉很奇怪,因为在我们写xml的时候,我们是写了控件的大小的:android:layout_width=”150dp” android:layout_height=”150dp”,或者用Java代码调用View.setLayoutParams(),这些都直接指定了view的大小,那么为社么还需要onMeasure呢?

现在我们想一下wrap_content这个这个属性。包裹内容。如果我们写了一个LinearLayout,并且设置了wrap_content值,那么这个LinearLayout的大小就会由它内部控件的大小来确定,此时,onMeasure方法便派上了用场。由于现在没有像上面150dp那样,直接给定大小,那么我们就需要知道内部子空间的大小,然后来计算自身的大小。实际上,measure方法的调用是一个递归的过程,从根view,一直到每个子view,通过这样的方法,我们就能知道每一个子view的大小,然后就可以测量出ViewGroup自身的大小。

onMeasure实际上只在ViewGroup的长或者宽是wrap_content时,才发挥真正作用,否则仅仅是递归调用子view的measure而已。

onMeasure方法的参数,widthMeasureSpec,heightMeasureSpec。关于这两个参数的意义,网上有很多,这里不再赘述,只谈一下下文要用到的东西。这两个参数包含了父布局想要子布局设置的大小,就是告诉子布局,我还有多少地方可以给你用(at_most),或者你必须用这么多地方(exactly)。这个两个参数是由父布局,子布局的layout_width,layout_height共同决定的。下面是一个关于该结论的测试记录。size,和mode是子布局widthMeasureSpec的内容。
1、外层 wrapped 内层wrapped size = 1080 mode = at_most
2、外层 wrapped 内层50dp size = 150 mode = exactly
3、外层 match_parent 内层50dp size = 150 mode = exactly
4、外层 match_parent 内层wrapped size = 1080 mode = at_most

measureChildren

既然谈到测量子控件,那么就需要用到measureChildren方法。这个方法的参数和onMeasure方法是完全相同的。当我们需要测量子控件的时候,直接调用measureChildren(widthMeasureSpec,heightMeasureSpec),参数来源于自身的onMeasure。在我写的过程中一直有个疑问,难道我们不应该给子布局重新设置下widthMeasureSpec,heightMeasureSpec的值吗?直接使用父布局的不会有问题吗?最后通过实验发现,measureChildren()内部已经为我们做了这些事,我们完全没有必要担心。

自定义ViewGroup的过程

onLayout方法,用来指定子控件的位置。这个方法比较好理解,通过调用getChildAt()方法获取子控件,然后调用子控件的layout方法,参数就是子控件左,上,右,下的位置。同样,layout方法也是会递归调用的。

总结

onMeasure调用是递归的。
onMeasure用来测量自身。
当ViewGroup是wrapp_content的时候,onMeasure内部需要获取子控件大小,来测量自身,这也是我们自定义控件重写onMeasure方法的意义。
measureChildren()的参数无需改变,传入自身onMeasure的参数即可。通过
child.getMeasureWidth获得子控件的测量宽度值。

onLayout调用是递归的。
onLayout用于指定内部控件的位置,通过child.layout(l,t,r,b)来实现。

自定义View只需要重写onMeasure方法,来告知父布局,“我”的大小。
自定义ViewGroup还需要重写onLayout来控制子控件的位置。

希望可以对学习android的各位有帮助。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值