View 绘制体系知识梳理(7) getMeasuredWidth 和 getWidth 的区别
前言
前几天被问到了getMeasuredWidth
和getWidth
之间的区别,因此回来看了一下源码,又顺便复习了一遍measure/layout/draw
的过程,有兴趣的同学可以看前面的几篇文章
- View 绘制体系知识梳理(3) - 绘制流程之 Measure 详解
- View 绘制体系知识梳理(4) - 绘制过程之 Layout 详解
- View 绘制体系知识梳理(5) - 绘制过程之 Draw 详解
一、getMeasuredWidth 和 getWidth 的定义
1.1 getMeasuredWidth
我们来看一下getMeasuredWidth
方法的内部实现:
/*** Like {@link #getMeasuredWidthAndState()}, but only returns the* raw width component (that is the result is masked by* {@link #MEASURED_SIZE_MASK}).** @return The raw measured width of this view.*/public final int getMeasuredWidth() {return mMeasuredWidth & MEASURED_SIZE_MASK;}
复制代码
这里可以看到,该方法返回的是setMeasuredDimensionRaw
中设置的mMeasuredWidth
的size
部分,也就是说,该方法返回的是在 测量阶段中计算出的宽度。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {boolean optical = isLayoutModeOptical(this);if (optical != isLayoutModeOptical(mParent)) {Insets insets = getOpticalInsets();int opticalWidth = insets.left + insets.right;int opticalHeight = insets.top + insets.bottom;measuredWidth += optical ? opticalWidth : -opticalWidth;measuredHeight += optical ? opticalHeight : -opticalHeight;}setMeasuredDimensionRaw(measuredWidth, measuredHeight);}private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {mMeasuredWidth = measuredWidth;mMeasuredHeight = measuredHeight;}
复制代码
1.2 getWidth
/*** Return the width of the your view.** @return The width of your view, in pixels.*/@ViewDebug.ExportedProperty(category = "layout")public final int getWidth() {return mRight - mLeft;}
复制代码
getWidth
的值是根据mRight
和mLeft
之间的差值计算出来的,在setFrame
方法中,会对View
的四个点坐标mLeft/mRigth/mTop/mBottom
进行赋值,它决定了View
在其父容器中所处的位置:
protected boolean setFrame(int left, int top, int right, int bottom) {boolean changed = false;if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {changed = true;mLeft = left;mTop = top;mRight = right;mBottom = bottom;//....}return changed;}
复制代码
而setFrame
就是在layout
过程中调用的:
public void layout(int l, int t, int r, int b) {int oldL = mLeft;int oldT = mTop;int oldB = mBottom;int oldR = mRight;//通过之前介绍的 setFrame 方法进行赋值。boolean changed = isLayoutModeOptical(mParent) ?setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {onLayout(changed, l, t, r, b);if (shouldDrawRoundScrollbar()) {if(mRoundScrollbarRenderer == null) {mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);}} else {mRoundScrollbarRenderer = null;}mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;ListenerInfo li = mListenerInfo;if (li != null && li.mOnLayoutChangeListeners != null) {ArrayList<OnLayoutChangeListener> listenersCopy =(ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();int numListeners = listenersCopy.size();for (int i = 0; i < numListeners; ++i) {listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);}}}}
复制代码
1.3 小结
在之前的两篇文章 View 绘制体系知识梳理(3) - 绘制流程之 Measure 详解 和 View 绘制体系知识梳理(4) - 绘制过程之 Layout 详解,我们介绍了measure
和layout
的内部实现,而getMeasuredWidth
和getWidth
就分别对应于上面这两个阶段获得的宽度,也就是说:
getMeasuredWidth
是measure
阶段获得的View
的原始宽度。getWidth
是layout
阶段完成后,其在父容器中所占的最终宽度
1.4 注释说明
下面是Google
文档中对于上面这两个方法的注释说明:
getMeasuredWidth
:
The width of this view as measured in the most recent call to measure().
This should be used during measurement and layout calculations only.
Use getWidth() to see how wide a view is after layout.Returns: the measured width of this view
复制代码
getWidth
Return the width of the your view.Returns: the width of your view, in pixels
复制代码
二、示例
我们用一个简单的示例,来演示getMeasuredWidth
和getWidth
的区别:
2.1 布局定义
首先定义一个自定义的LinearLayout
,它包含两个子View
,在xml
中它们的宽度都被指定为200dp
。
<?xml version="1.0" encoding="utf-8"?>
<com.demo.lizejun.repoopt.WidthDemoLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Viewandroid:background="@android:color/holo_blue_bright"android:layout_width="200dp"android:layout_height="100dp"/><Viewandroid:background="@android:color/holo_orange_light"android:layout_width="200dp"android:layout_height="100dp"/>
</com.demo.lizejun.repoopt.WidthDemoLayout>
复制代码
2.2 重写 onLayout 方法
在WidthDemoLayout
中,我们重写它的onLayout
方法,对它的子View
重新摆放,并打印出getMeasuredWidth
和getWidth
方法的值:
public class WidthDemoLayout extends LinearLayout {public WidthDemoLayout(Context context) {super(context);}public WidthDemoLayout(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public WidthDemoLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);int childCount = getChildCount();for (int i = 0; i < childCount; i++) {View child = getChildAt(i);if (i == childCount - 1) {child.layout(child.getLeft() ,child.getTop(), child.getRight() + 400, child.getBottom());}Log.d("WidthDemoLayout", "measuredWidth=" + child.getMeasuredWidth() + ",width=" + child.getWidth());}}
}
复制代码
输出的结果为:
>> 12-04 12:48:58.788 24935-24935/com.demo.lizejun.repoopt D/WidthDemoLayout: measuredWidth=800,width=800
>> 12-04 12:48:58.788 24935-24935/com.demo.lizejun.repoopt D/WidthDemoLayout: measuredWidth=800,width=1200
复制代码
最终展示的时候,虽然我们在xml
中指定了相同的宽度,但是最终显示是以getWidth
为准:
更多文章,欢迎访问我的 Android 知识梳理系列:
- Android 知识梳理目录:www.jianshu.com/p/fd82d1899…
- Android 面试文档分享:www.jianshu.com/p/8456fe6b2…
View 绘制体系知识梳理(7) getMeasuredWidth 和 getWidth 的区别相关推荐
- View 绘制体系知识梳理(4) 绘制过程之 Layout 详解
一.布局的起点 - performTraversals 和前面分析测量过程类似,整个布局的起点也是在ViewRootImpl的performTraversals当中: private void per ...
- View绘制体系(三)——AttributeSet与TypedArray详解
View绘制体系(三)--AttributeSet与TypedArray详解 前言 上篇博客中讲了LayoutInflater.inflate机制,其中提到了AttributeSet和XmlPullP ...
- 《软件工程与实践》 |(九)软件工程新技术及体系 知识梳理
系列索引: <软件工程与实践>第三版 软件工程课程知识梳理 目录 系列索引: <软件工程与实践>第三版 软件工程课程知识梳理 本章重难点: 9.1 软件工程新技术 9.1.1 ...
- getMeasuredWidth和getWidth的区别
View的getWidth()和getMeasuredWidth()有什么区别吗? View的高宽是由View本身和Parent容器共同决定的. getMeasuredWidth()和getWidth ...
- View 事件传递体系知识梳理(1) 事件分发机制
一.事件分发概述 1.1 事件分发的关键方法 对于ViewGroup来说,与事件分发相关的方法包括: public boolean dispatchTouchEvent(MotionEvent eve ...
- 【Android View绘制体系】invalidate
invalidate内部思想 invalidate的调用流图 View.invalidateInternal 打上DIRTY标记 为后面Draw做准备 mPrivateFlags |= PFLAG_D ...
- 【Android View绘制体系】requestLayout
如下为View的requestLayout: 经历了两步: 增加自身标记mPrivateFlags为PFLAG_FORCE_LAYOUT 调用父视图的requestLayout()方法.ViewGro ...
- 动画体系知识梳理(1) 转场动画 ContentTransition 理论篇
一.概述 在Android 5.0当中,Google基于Android 4.4中的Transition框架引入了转场动画,设计转场动画的目的,在于让Activity之间或者Fragment之间的切换更 ...
- Loader 知识梳理(2) initLoader和restartLoader的区别
一.概述 在前面的一篇文章中,我们分析了LoaderManager的实现,里面涉及到了很多的细节问题,我们并不需要刻意地记住每个流程,之所以需要分析,以后在使用的过程中,如果遇到问题了,再去查看相关的 ...
最新文章
- 如何理解numpy.nan_to_num
- DVWA的安装与简单使用
- 阿里云二面:你对限流了解多少?
- JavaScript 技术篇-js代码获取当前操作系统信息、浏览器版本信息实例演示,windows NT版本对照表
- python是什么学了有什么用处_学python有什么用途 就业方向有哪些
- [转]inux Kernel部分选项意义
- wdr和hdr的区别
- javascript对象包含哪些要素_让人迷糊的JavaScript对象(Object一)
- 如何revert一个merged branch上所有的改动
- .net mysql 序号_MYSQL如何自动为查询数据的结果编上序号详解
- HTML做出7个网页,HTML适用于除IE 7以外的每个网页浏览器。
- 实验楼Python项目
- 创维酷开电视能换成android系统吗,创维酷开电视怎么系统升级【图文教程】
- 8数据提供什么掩膜产品_喜茶、茶百道、书亦、古茗8月外卖热销产品数据全解析...
- 功能测试项目——酒店管理系统
- Android毕业设计选题依据,毕业设计选题依据、目的意义、
- 2020 — 只争朝夕,不负韶华
- 均质机工作原理动画_高压均质机结构图.doc
- 信息安全三要素(CIA):
- 成功路上并不拥挤 因为坚持的人不多
热门文章
- zabbix3.0.3-源码安装
- javascript:void(0)的作用示例
- Puppet基础篇5-如何建立master和agent之间的认证关系
- Three20 NetWork
- 如何在 Active Directory 中还原已删除的用户帐户及其组成员身份
- 谷歌再次修复已遭利用的两枚高危0day (CVE-2020-16009/16010)
- 【通告更新】Apache Tomcat服务器文件包含漏洞安全风险通告第三次更新
- LeetCode笔记:39. Combination Sum
- android与服务器交互总结(json,post,xUtils,Volley)
- 开源大数据周刊-第21期