Android的onMeasure和onLayout And MeasureSpec揭秘
Android中自定义ViewGroup最重要的就是onMeasure和onLayout方法,都需要重写这两个方法,ViewGroup绘制 的过程是这样的:onMeasure → onLayout → DispatchDraw
- 其实我觉得官方文档解释有大大的问题,刚开始一直很疑惑onMeasure和onLayout是什么意思,看了很多资料后豁然开朗,总结如下
首先要知道ViewGroup是继承View的,后面的解释跟View有关。ViewGourp可以包含很多个View,View就是它的孩子,比如LinearLayout布局是一个ViewGroup,在布局内可以放TextEdit、ImageView等等常用的控件,这些叫子View,当然不限于这个固定的控件。
onMeasure → onLayout → DispatchDraw:onMeasure负责测量这个ViewGroup和子View的大小,onLayout负责设置子View的布局,DispatchDraw就是真正画上去了。
onMeasure
官方解释:
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = MeasureSpec.getSize(widthMeasureSpec); //获取ViewGroup宽度
- int height = MeasureSpec.getSize(heightMeasureSpec); //获取ViewGroup高度
- setMeasuredDimension(width, height); //设置ViewGroup的宽高
- int childCount = getChildCount(); //获得子View的个数,下面遍历这些子View设置宽高
- for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- child.measure(viewWidth, viewHeight); //设置子View宽高
- }
- }
- 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;
- }
- mMeasuredWidth = measuredWidth; //这就是保存到类变量
- mMeasuredHeight = measuredHeight;
- mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
- }
- public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
- <span style="white-space:pre"> </span>.........
- <span style="white-space:pre"> </span>// measure ourselves, this should set the measured dimension flag back
- onMeasure(widthMeasureSpec, heightMeasureSpec);
- <span style="white-space:pre"> </span>..........
- }
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
- getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
- }
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- int mTotalHeight = 0;
- // 当然,也是遍历子View,每个都要告诉ViewGroup
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View childView = getChildAt(i);
- // 获取在onMeasure中计算的视图尺寸
- int measureHeight = childView.getMeasuredHeight();
- int measuredWidth = childView.getMeasuredWidth();
- childView.layout(left, mTotalHeight, measuredWidth, mTotalHeight + measureHeight);
- mTotalHeight += measureHeight;
- }
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int width = MeasureSpec.getSize(widthMeasureSpec); //获取真实width
- int height = MeasureSpec.getSize(heightMeasureSpec); //获取真实height
- setMeasuredDimension(width, height); //设置ViewGroup的宽高
- for (int i = 0; i < getChildCount(); i++) {
- getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); //遍历孩子设置宽高
- }
- }
- public static class MeasureSpec {
- private static final int MODE_SHIFT = 30; //
- private static final int MODE_MASK = 0x3 << MODE_SHIFT;
- public static int getMode(int measureSpec) {
- return (measureSpec & MODE_MASK);
- }
- public static int getSize(int measureSpec) {
- return (measureSpec & ~MODE_MASK);
- }
- }
发现解析前后的值差很远,再结合源代码 widthMeasureSpec & ~ MODE_MASK,运算后刚好匹配得到width。运算方法:0x3=0011, 它向左移位30位,得到1100 0000 .....(1后面一共有30个0.) ~取反后就是0011 1111……(0后面有30个1). 上面的widthMeasureSpec是1073742304,转换成二进制是 0100 0000 0000 0000 0000 0001 1110 0000,和前面那个 ~MODE_MASK &之后(注意MODE_MASK要先取反再与widthMeasureSpec),最前面那个2个1就去掉了,widthMeasureSpec只留下了后面一段有1,即得到0000 …(省略16个0)… 0001 1110 0000,得到的值转换成 十进制刚好是480,完美,转换后得到了真实的width。手机的屏幕刚好是480*854,这是小米1的屏幕。
Android的onMeasure和onLayout And MeasureSpec揭秘的更多相关文章
- 【转】ViewGroup的onMeasure和onLayout分析
ViewGroup的onMeasure和onLayout分析 一个Viewgroup基本的继承类格式如下: 1 import android.content.Context; 2 import and ...
- ANDROID自己定义视图——onLayout源代码 流程 思路具体解释
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 简单介绍: 在自己定义view的时候.事实上非常easy.仅仅须要知道3步骤: 1.測量- ...
- 继承ViewGroup学习onMeasure()和onLayout()方法
在继承ViewGroup类时,需要重写两个方法,分别是onMeasure和onLayout. 1,在方法onMeasure中调用setMeasuredDimension方法void android.v ...
- 通过重写ViewGroup学习onMeasure()和onLayout()方法
在继承ViewGroup类时,需要重写两个方法,分别是onMeasure和onLayout. 1,在方法onMeasure中调用setMeasuredDimension方法 void android. ...
- [转]Android View.onMeasure方法的理解
转自:http://blog.sina.com.cn/s/blog_61fbf8d10100zzoy.html Android View.onMeasure方法的理解 View在屏幕上显示出来要先经过 ...
- 自定义控件详解(五):onMeasure()、onLayout()
前言: 自定义控件的三大方法: 测量: onMeasure(): 测量自己的大小,为正式布局提供建议 布局: onLayout(): 使用layout()函数对所有子控件布局 绘制: onDraw() ...
- Android下如何理解onMeasure,onLayout的过程
在Android中view如何完成绘制这个过程介绍了很多,但是很多理论化的东西,最近重新整理一下,通俗的讲解一下. View绘制过程就好比你向银行贷款, 在执行onMeasure的时候,好比银行告诉你 ...
- Android onMeasure 方法的测量规范MeasureSpec
一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求.一个MeasureSpec由大小和模式组成.它有三种模式:UNSPECIFIED(未 ...
- android自定义控件 onMeasure() 测量尺寸
上次讲的自定义控件刷新点屏幕的任意地方都会刷新,而且在xml里自定义控件下面放一个textview的话,这个TextView是显示不出来的,不只这个,以前的几个自定义控件都是 为什么呢?今天来讲下on ...
随机推荐
- 炫酷的jquery瀑布流
最近做了一个瀑布流效果,思路很简单 首先计算屏幕一行可以放多少个图片,然后在第二行开始,计算每一列的高度并取出最小值,将新图片加载在最小列高度下,如此循环,并且设定一个条件,当滑动到一定距离后,开始重 ...
- BZOJ 3732 题解
3732: Network Description 给你N个点的无向图 (1 <= N <= 15,000),记为:1…N. 图中有M条边 (1 <= M <= 30,000) ...
- jquery 最简单的动画效果
<p style="border: 1px solid red"> 我会慢慢变大 </p> <a>dianji</a> <sc ...
- UpdatePanel完成后调用js
引言: asp.net 微软引入了UpdatePanel 使用起来很方便 如果 我们想UpdatePanel加载完成后做一些事情 需要使用js <script type="text/j ...
- 修改linux运行级别
1.Linux下的7个运行级别 0 系统停机模式,系统默认运行级别不能设置为0,否则不能正常启动,机器关闭. 1 单用户模式,root权限,用于系统维护,禁止远程登陆,就像Windows下的安全模式登 ...
- 一个简单的零配置命令行HTTP服务器 - http-server (nodeJs)
http-server 是一个简单的零配置命令行HTTP服务器, 基于 nodeJs. 如果你不想重复的写 nodeJs 的 web-server.js, 则可以使用这个. 安装 (全局安装加 -g) ...
- python--range()函数
1: >>> range(10, 0, -1) [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] >>> range(10) [0, 1, 2, 3, ...
- VTK GetScalarPointer() and GetScalarComponentAsFloat() not work
I am using VTK 5.10.1 with VS 2010, and the following example does not work on my machine: http://ww ...
- Ubuntu FTP 配置
1. apt-get install vsftpd 2. vim /etc/vsftp.conf #禁止匿名访问 anonymous_enable=NO #接受本地用户 local_enable=YE ...
- java代码实现打包多个文件下载功能
//传入对应的需要打包的file 集合对象 //文件打包下载 public static HttpServletResponse downLoadFiles(List<File> ...