我们直接查看View工作原理源码,整理出以下三个方法,都是View类中的方法。
onMeasure()方法
getSuggestMinimumWidth()方法
getDefaultSize()方法
onMeasure() 方法
测量方法onMeasure() 接受父视图施加的宽度和高度“测量规范”。
//widthMeasureSpec 父类的宽度测量标准
//heightMeasureSpec 父类的身高测量标准
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize=getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int heightSize=getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasureDimension(宽度尺寸, 高度尺寸);
}getSuggestedMinimumWidth() 方法
这个方法只有在父容器对子View的宽度没有任何限制的情况下才有效。一般用于系统内部测量,这里不做研究。
getDefaultSize() 方法
这是调查的重点。一般来说,子视图的高度是由父视图的‘测量规范’决定的。
公共静态int getDefaultSize(int size, intmeasureSpec) {
int 结果=大小;
int specMode=MeasureSpec.getMode(measureSpec);
int specSize=MeasureSpec.getSize(measureSpec);
开关(规格模式){
案例MeasureSpec.UNSPECIFIED: {
结果=大小;
}
休息;
案例MeasureSpec.exactly:
案例MeasureSpec.at_most: {
结果=规格大小;
}
休息;
}
返回结果;
}结论:无论子View的高度是match_parent、wrap_content还是特定的高度值(比如100px),测量的高度都是父容器的高度。
直接继承View的自定义控件需要重写onMeasure()方法,在wrapping_content时设置自己的大小。否则,在布局中使用wrap_content相当于使用match_parent。指定的默认内部宽度/高度(mWidth和mHeight)没有固定依据,可以根据需要灵活指定。如果你看一下TextView、ImageView等的源码就可以知道,它们的onMeasure()方法都针对wrap_content的情况进行了特殊处理。
以上就是这篇文章的内容。下面的源代码仅供喜欢深入研究的读者参考。
以下是TextView的onMeasure()方法的源码
@覆盖
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 高度;
BoringLayout.Metrics 无聊=UNKNOWN_BORING;
BoringLayout.MetricshintBoring=UNKNOWN_BORING;
如果(mTextDir==null){
mTextDir=getTextDirectionHeuristic();
}
int des=-1;
布尔值fromexisting=false;
最终浮点数widthLimit=(widthMode==MeasureSpec.AT_MOST)
? (浮动) widthSize : Float.MAX_VALUE;
if (widthMode==MeasureSpec.EXACTLY) {
//父母已经告诉我们要多大。就这样吧。
宽度=宽度尺寸;
} 别的{
if (mLayout !=null mEllipsize==null) {
des=期望的(mLayout);
}
如果(des 0){
无聊=BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
如果(无聊!=空){
mBoring=无聊;
}
} 别的{
来自现有=真;
}
if (无聊==null || 无聊==UNKNOWN_BORING) {
如果(des 0){
des=(int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0,
mTransformed.length(), mTextPaint, mTextDir, widthLimit));
}
宽度=des;
} 别的{
宽度=钻孔.宽度;
}
最终的Drawables dr=mDrawables;
如果(博士!=空){
宽度=Math.max(宽度, dr.mDrawableWidthTop);
宽度=Math.max(宽度, dr.mDrawableWidthBottom);
}
if (mHint !=null) {
int 提示Des=-1;
int 提示宽度;
if (mHintLayout !=null mEllipsize==null) {
提示Des=期望的(mHintLayout);
}
if (hintDes 0) {
hintBoring=BoringLayout.isBoring(mHint, mTextPaint, mTextDir, mHintBoring);
if (hintBoring !=null) {
mHintBoring=提示Boring;
}
}
if (hintBoring==null ||hintBoring==UNKNOWN_BORING) {
if (hintDes 0) {
hintDes=(int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0,
mHint.length(), mTextPaint, mTextDir, widthLimit));
}
提示宽度=提示Des;
} 别的{
提示宽度=提示Boring.width;
}
if (hintWidth 宽度) {
宽度=提示宽度;
}
}
宽度+=getCompoundPaddingLeft() + getCompoundPaddingRight();
if (mMaxWidthMode==EMS) {
宽度=Math.min(宽度, mMaxWidth * getLineHeight());
} 别的{
宽度=Math.min(宽度, mMaxWidth);
}
如果(mMinWidthMode==EMS){
宽度=Math.max(宽度, mMinWidth * getLineHeight());
} 别的{
宽度=Math.max(宽度, mMinWidth);
}
//检查我们的最小宽度
宽度=Math.max(宽度, getSuggestedMinimumWidth());
if (widthMode==MeasureSpec.AT_MOST) {
宽度=Math.min(widthSize, 宽度);
}
}
int Want=width - getCompoundPaddingLeft() - getCompoundPaddingRight();
int unpaddedWidth=想要;
如果(mHorizontallyScrolling)想要=VERY_WIDE;
int 提示想要=想要;
inthintWidth=(mHintLayout==null) ?提示想要: mHintLayout.getWidth();
如果(mLayout==null){
makeNewLayout(想要,提示想要,无聊,提示无聊,
宽度- getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
} 别的{
最终布尔layoutChanged=(mLayout.getWidth() !=Want) || (提示宽度!=提示想要)
|| (mLayout.getEllipsizedWidth()
!=宽度- getCompoundPaddingLeft() - getCompoundPaddingRight());
最终布尔widthChanged=(mHint==null) (mEllipsize==null)
(想要mLayout.getWidth())
(mLayout实例BoringLayout
|| (从现有的des=0 des=想要));
最终布尔值maximumChanged=(mMaxMode !=mOldMaxMode) || (mMaximum!=mOldMaximum);
如果(布局更改|| 最大更改){
if (!maximumChanged widthChanged) {
mLayout.increaseWidthTo(想要);
} 别的{
makeNewLayout(想要,提示想要,无聊,提示无聊,
宽度- getCompoundPaddingLeft() - getCompoundPaddingRight(), false);
}
} 别的{
//没有任何改变
}
}
if (heightMode==MeasureSpec.EXACTLY) {
//父母已经告诉我们要多大。就这样吧。
高度=高度尺寸;
mDesiredHeightAtMeasure=-1;
} 别的{
int 期望=getDesiredHeight();
高度=期望的;
mDesiredHeightAtMeasure=期望的;
if (heightMode==MeasureSpec.AT_MOST) {
高度=Math.min(期望值, heightSize);
}
}
int unpaddedHeight=高度- getCompoundPaddingTop() - getCompoundPaddingBottom();
if (mMaxMode==LINES mLayout.getLineCount() mMaximum) {
unpaddedHeight=Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum));
}
/*
* 我们没有让makeNewLayout() 注册来将光标带入视图,
* 因此,如果有任何可能需要的话,请在此处执行此操作。
*/
if (mMovement !=null
|| mLayout.getWidth() 未填充的宽度
|| mLayout.getHeight() unpaddedHeight) {
注册ForPreDraw();
} 别的{
滚动到(0, 0);
}
OK,关于Android View层绘制原理:父视图高度设置为match属性解析和的内容到此结束了,希望对大家有所帮助。
【Android View层绘制原理:父视图高度设置为match属性解析】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
终于找到一篇关于 Android View 绘制的文章了!一直想深入了解这个部分。
有18位网友表示赞同!
Match_parent 经常用到,这次好好学习下它的具体原理吧。
有18位网友表示赞同!
希望能详细讲解一下不同View的绘制顺序和父视图尺寸的影响。
有10位网友表示赞同!
Android 的 View 绘制机制还挺复杂的,这篇文章能让我看得更加清晰吗?
有11位网友表示赞同!
看了很多篇Android开发的文章,没找到像这篇文章这样专注于View绘制的。
有5位网友表示赞同!
希望作者能详细介绍一下如何调试布局和绘制的过程。
有5位网友表示赞同!
我对 View 的测量、布局和绘图这个环节一直不太理解,希望能详细解释哦!
有12位网友表示赞同!
想了解一下 match_parent 在不同场景下的行为区别。
有15位网友表示赞同!
学习 Android 开发一段时间了,但对 View 绘制的理解还比较浅显,期待这篇文章能给我新的点拨。
有16位网友表示赞同!
View 的绘制和布局关系密切吧? 这篇文章会不会讲到这些关联内容?
有7位网友表示赞同!
希望能给出一些解决常见 View 绘制问题的技巧和经验分享。
有16位网友表示赞同!
我经常遇到不同View显示尺寸不一致的情况,这篇文章能帮我找到原因吗?
有10位网友表示赞同!
学习 Android 的一个关键点就是了解其绘制机制,这本书很及时!
有8位网友表示赞同!
看标题好像能解决很多布局问题啊,期待学习!
有18位网友表示赞同!
我对 Android 开发的新手,希望这个文章能让我快速入门 View 绘制。
有13位网友表示赞同!
父视图高为 match_parent 的情况下 ,不同的孩子View的绘制有什么区别吗?
有8位网友表示赞同!
这篇文章能不能结合实际案例分析一下,更直观易懂。
有8位网友表示赞同!
学习 Android 总是需要反复练习,这篇文章能帮助我更好地理解 View 绘制。
有10位网友表示赞同!
我会把这篇关于 Android View 绘制的文章分享给我的朋友们!
有20位网友表示赞同!
Android 的技术含量很高,学习这个知识点很不容易,谢谢作者的分享!
有18位网友表示赞同!