概述
转载自 https://www.cnblogs.com/xqxacm/p/6673469.html
和 https://blog.csdn.net/superxukai88/article/details/78675686
并写了一些自己的总结
前言:
自定义控件的三大方法:
测量: onMeasure(): 测量自己的大小,为正式布局提供建议
布局: onLayout(): 使用layout()函数对所有子控件布局
绘制: onDraw(): 根据布局的位置绘图
onDraw() 里面是绘制的操作,可以看下其他的文章,下面来了解 onMeasure()和onLayout()方法。
一、onMeasure()、测量
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
参数即父类传过来的两个宽高的"建议值",即把当前view的高设置为:heightMeasureSpec ;宽设置为:widthMeasureSpec
这个参数不是简单的整数类型,而是2位整数(模式类型)和30位整数(实际数值) 的组合
其中模式分为三种:
①、UNSPECIFIED(未指定),父元素不对自元素施加任何束缚,子元素可以得到任意想要的大小;UNSPECIFIED=00000000000000000000000000000000
②、EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;EXACTLY =01000000000000000000000000000000
③、AT_MOST(至多),子元素至多达到指定大小的值。 他们对应的二进制值分别是: AT_MOST =10000000000000000000000000000000
最前面两位代表模式,分别对应十进制的0,1,2;
获取模式int值 和 获取数值int值的方法:
1. int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
2. int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
3. int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
4. int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
模式的值有:
MeasureSpec.AT_MOST = 2
MeasureSpec.EXACTLY = 1
MeasureSpec.UNSPECIFIED = 0
上面我们知道了 onMeasure(int widthMeasureSpec, int heightMeasureSpec) 方法参数的意义
下面了解参数对应的三个模式分别对应的意义:
每一个模式都对应的xml布局中的一个值
wrap_content — MeasureSpec.AT_MOST
match_parent — MeasureSpec.EXACTLY
具体值 — MeasureSpec.UNSPECIFIED
注意:
—当模式是MeasureSpec.AT_MOST时,即wrap_content时,此时传入的int widthMeasureSpec, int heightMeasureSpec的数值部分(后30位)实际上就是父亲建议的尺寸数值,(如果父亲只有一个子view,数值就是父亲自己的尺寸,多个子view的LinearLayout传递的值是安置完之前的子view剩下的空间尺寸),因此在onMeasure里不做其他操作,view仍然会符合父亲的建议.
PS: 但需要注意的是,如果直接自定义一个View,宽高为wrap_content, 则最后绘制的时候view是占满整个父View的(假设父view只有这一个儿子),这是因为上面说的,传过来的是父亲的尺寸,但如果自定义View继承了像TextView之类的,最后还调用了super.onMeasure,则显示的时候大小是根据其内容显示的,这是因为这些TextView在自己的onMeasure里又做了处理,使得其根据内容的大小而变化。
—当模式是MeasureSpec.EXACTLY时,即match_parent时,此时传入的int widthMeasureSpec, int heightMeasureSpec的数值部分(后30位)实际上也是父亲建议的尺寸数值(如果父亲只有一个子view,数值就是父亲自己的尺寸,多个子view的LinearLayout传递的值是安置完之前的子view剩下的空间尺寸),因此在onMeasure里不做其他操作,view仍然会符合父亲的建议
PS:(AT_MOST与EXACTLY:如果在onMeasure中不做任何处理而调用setMeasureDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)))来设置尺寸,,或者在基类的onMeasure中不做任何额外处理而调用super.onMeasure().那么这两个模式没有任何区别(都是用父亲建议的大小设置自己的大小,而且两个模式父亲建议的大小都一样)。因此若使用AT_MOST一般都要在onMeasure中根据mode不同而设置view尺寸为不同的大小(如同TextView做的那样)
—当模式是MeasureSpec.UNSPECIFIED时,即具体数值时,此时传入的int widthMeasureSpec, int heightMeasureSpec的数值部分(后30位)实际是具体指定的数字,因此在onMeasure里不做其他操作,子view会符合父亲的建议,即变成它自己设定的尺寸,尽管这里的数字大小是不做限制的,但当绘制的时候,父亲会clip掉自己尺寸之外的子view的部分。要避免的话,需设置子view的顶级祖先ViewGroup的clipChildren属性为false,而且它的父亲必须不是RelativeLayout(即不clip有两个条件,1.顶级祖先view设置clipChildren=false。2.父view必须不是RelativeLayout,PS:父view设置不设置clipChildren无所谓,顶级祖先必须设置)
二、onLayout() 、 布局
onLayout方法是ViewGroup中子View的布局方法,用于放置子View的位置。放置子View很简单,只需在重写onLayout方法,然后获取子View的实例,调用子View的layout方法实现布局。在实际开发中,一般要配合onMeasure测量方法一起使用。
onLayout方法:
@Override
protected
abstract void onLayout(boolean
changed,
intl,
int t,
int r,
int b);
该方法在ViewGroup中定义是抽象函数,继承该类必须实现onLayout方法,而ViewGroup的onMeasure并非必须重写的。View的放置都是根据一个矩形空间放置的,onLayout传下来的l,t,r,b分别是放置父控件的矩形可用空间(除去margin和padding的空间)的左上角的left、top以及右下角right、bottom值。
layout方法:
public
void layout(int
l, int
t, int
r, int
b);
该方法是View的放置方法,在View类实现。调用该方法需要传入放置View的矩形空间左上角left、top值和右下角right、bottom值。这四个值是相对于父控件而言的。例如传入的是(10, 10, 100, 100),则该View在距离父控件的左上角位置(10, 10)处显示,显示的大小是宽高是90(参数r,b是相对左上角的),这有点像绝对布局。
平常开发所用到RelativeLayout、LinearLayout、FrameLayout…这些都是继承ViewGroup的布局。这些布局的实现都是通过都实现ViewGroup的onLayout方法,只是实现方法不一样而已。
最后
以上就是潇洒大地为你收集整理的onMeasure()和onLayout()总结的全部内容,希望文章能够帮你解决onMeasure()和onLayout()总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复