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 ...
随机推荐
- NOIP 2013 货车运输【Kruskal + 树链剖分 + 线段树 】【倍增】
NOIP 2013 货车运输[树链剖分] 树链剖分 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在 ...
- URAL 1427. SMS(DP+单调队列)
题目链接 我用的比较传统的办法...单调队列优化了一下,写的有点搓,不管怎样过了...两个单调队列,存两个东西,预处理一个标记数组存... #include <iostream> #inc ...
- 【BZOJ2223/3524】[Coci 2009]PATULJCI
Description Input Output 10 3 1 2 1 2 1 2 3 2 3 3 8 1 2 1 3 1 4 1 5 2 5 2 6 6 9 7 10 Sample Input ...
- Java_一致性哈希算法与Java实现
摘自:http://blog.csdn.net/wuhuan_wp/article/details/7010071 一致性哈希算法是分布式系统中常用的算法.比如,一个分布式的存储系统,要将数据存储到具 ...
- MongoDB设置访问权限、设置用户
MongoDB已经使用很长一段时间了,基于MongoDB的数据存储也一直没有使用到权限访问(MongoDB默认设置为无权限访问限制),今天特地花了一点时间研究了一下,研究成果如下: 注:研究成果基于W ...
- Compound Words
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=91209#problem/C 题意: 有一堆按照字典序排好的字符串,问你有多 ...
- 使用Privoxy做智能代理切换
使用Privoxy做智能代理切换 You take the blue pill, the story ends, you wake up in your bed, and believe whatev ...
- php链接mysql数据库
php连接数据库有三种方法,刚刚发现通过mysql_connect,mysql_query连接已被废弃,而现在推荐的是通过“面向对象方法”和“PDO方法”连接数据库. 而我在使用面向对象的方法连接时, ...
- HTML静态网页导航制作
普通导航栏制作 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- svn学习笔记(1)入门学习----安装及创建运行仓库
学习及使用svn有一段时间了,但是以前学习的时候不怎么用,现在用只是简单的更新上传,又把基本理论忘了.为了以后自己看自己的笔记回忆,特此记录 svn学习博客:http://www.cnblogs.co ...