前言

  View的绘制过程分为 measure、layout、draw三个步骤,接下来对这三个步骤逐一进行研究。

measure方法的签名

public final void measure(int widthMeasureSpec, int heightMeasureSpec);

  measure方法用来测量View的尺寸。两个参数widthMeasureSpec/heightMeasureSpec声明了Parent View所能提供的宽/高。

  需要注意的是,widthMeasureSpec/heightMeasureSpec 这两个 int 型的参数是复合参数(compound parameters)。jvm中以32bit来存储int,最高两位表示“mode”,后面30位才是具体的数值。在View.java中有下面两个方法

        /*** Extracts the mode from the supplied measure specification.** @param measureSpec the measure specification to extract the mode from* @return {@link android.view.View.MeasureSpec#UNSPECIFIED},*         {@link android.view.View.MeasureSpec#AT_MOST} or*         {@link android.view.View.MeasureSpec#EXACTLY}*/public static int getMode(int measureSpec) {return (measureSpec & MODE_MASK);}/*** Extracts the size from the supplied measure specification.** @param measureSpec the measure specification to extract the size from* @return the size in pixels defined in the supplied measure specification*/public static int getSize(int measureSpec) {return (measureSpec & ~MODE_MASK);}

  看到了吧,使用位操作&来获取最高两位的mode。2^2=4,这里只有用到了3种,它们分别的含义入下

  • UNSPECIFIED-ParentView对子View没有约束,后者可以是任意大小
  • AT_MOST-ParentView规定了尺寸上限,子View的大小不可以超过这个上限
  • EXACTLY-ParentView规定了子View的宽高,子View只能是这个宽高

  measure方法本身是声明为final的,CustomView必须实现自己的onMeasure方法,以便View.measure对此进行回调。在实现自己的CustomView.onMeasure之前,先来看看View中默认的onMeasure方法。

onMeasure

  在自定义View中,往往需要重写onMeasure方法,来设置View的measured width/height。要注意的一点是,计算完成后,必须调用setMeasuredDimension(int, int)来设置宽高,不然在上层measure方法会抛出IllegalStateException。自定View计算出的宽/高必须满足最小宽/高(通过getSuggestedMinimumWidth()、getSuggestedMinimumHeight()获取)。当然也可以在自定义View的onMeasure方法中直接调用View.onMeasure,如下

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

  然而,View默认的onMeasure实现逻辑非常简单,恐怕不能满足自定义View的需求。

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}

  View.onMeasure简单粗暴地调用了setMeasuredDimension来设置measuredWidth/measuredHeight。其中使用的getDefaultSize(int, int)方法如下

    public static int getDefaultSize(int size, int measureSpec) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.UNSPECIFIED:result = size;break;case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = specSize;break;}return result;}

  逻辑很简单,一个switch/case语句,根据SpecMode来判断返回。若为UNSPECIFIED,则返回minimumWidth;若为AT_MOST/EXACTLY,返回SpecWidth。

  到此为止,View的measure过程已经完成了。对于ViewGroup,可以猜想,它的onMeasure方法,是把所有子View的onMeasure做一次相加。我们来看一下具体是不是这样做的。

ViewGroup.measure

  ViewGroup继承了View类,理所应当地,我们试图在ViewGroup中查找是否重写了onMeasure方法——未果。不过我们惊喜地发现了measureChildren这个方法——用来遍历所有children,对每一个child进行measure

    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {final int size = mChildrenCount;final View[] children = mChildren;for (int i = 0; i < size; ++i) {final View child = children[i];if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {measureChild(child, widthMeasureSpec, heightMeasureSpec);}}}

  measureChild中,将ViewGroup的padding加入了计算,最后调用child.measure,这里不予深究,也不再贴出代码。

  ViewGroup.java本身并没有重写onMeasure方法,在它的具体实现中,onMeasure根据具体情况,将children的measured size进行求和处理,具体可以参阅FrameLayout/LiearLayout/RelativeLayout 的代码。

小结

  对于measure过程的分析就到这里,下一篇我们继续探讨onLayout过程。

转载于:https://www.cnblogs.com/maozhige/p/4761560.html

Android UI 绘制过程浅析(二)onMeasure过程相关推荐

  1. 【Android View绘制之旅】Draw过程

    出效果:绘制 经过前面的准备工作 :[Android View绘制之旅]Measure过程,[Android View绘制之旅]Layout过程 我们的视图具备了宽高数据,位置数据,现在到了激动人心的 ...

  2. Android UI绘制流程分析(三)measure

    源码版本Android 6.0 请参阅:http://androidxref.com/6.0.1_r10 本文目的是分析从Activity启动到走完绘制流程并显示在界面上的过程,在源码展示阶段为了使跟 ...

  3. Android View的工作流程(二) measure过程

     一.View的measure过程 View的measure过程是由View的measure方法完成的,他是一个被final关键字修饰的方法,我们无法重写该方法,但是measure方法中会调用onMe ...

  4. 【Android View绘制之旅】Layout过程

    1.为什么要进行Layout? 在[Android View绘制之旅]View之测量Measure过程后,View我们得到View的宽高,但光只有宽高值是不足以反映视图的,更需要知道View所在的位置 ...

  5. android ui框架详解,多图详解 “Android UI”设计官方教程(二)

    编者注:本文为Android的官方开发者博客发了一份幻灯片的翻译文档的第二部分,专门介绍了一些Android UI设计的小贴士,我们在介绍这个幻灯片的第一部分<多图详解 "Androi ...

  6. 【Android View绘制之旅】Measure过程

    1.为什么要进行Measure? 替人做了原本应该做的工作.在写xml的时候,布局参数如 wrap_content,match_parent,weight 等等给我们开发界面的时候带来方便,但是机器可 ...

  7. Framework学习之路(一)—— UI绘制深入源码分析

    Framework学习之路(一)-- UI绘制深入源码分析 本篇为笔者对Android SDK 33版本的UI绘制入口进行追踪的过程,主要作笔记作用.由于笔者经验尚浅,水平也有限,所以会存在很多不足的 ...

  8. android drawtext 方法,Android 文字绘制(DrawText)技术总结

    这里的绘制文字不是直接调用TextView.setText(String content)去展示文字内容.而是在View上面通过 canvas.drawText(text, x, y,textPain ...

  9. Android 系统性能优化(34)---Android UI 性能优化

    Android官网 Slow rendering:个人觉得非常有价值,比如指出 对象分配.垃圾回收(GC).线程调度以及Binder调用 是Android系统中常见的卡顿原因,更重要的是给出了定位和解 ...

最新文章

  1. python 删除字符串中重复的元素
  2. Pycharm出现out of memory 的终极解决方法
  3. 深度神经网络:WX+b vs XW+b
  4. 机器学习-学习资源整理
  5. 安装composer出现链接补上的问题
  6. 【学亮IT手记】SpringMVC增删改查+map数据返回Controller层代码示例
  7. 某知名公司ERP数据库结构[5]
  8. 聚焦数字化智慧安防的新型社区
  9. Idea springboot应用,启动报错:org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputExcept
  10. plpgsql语句的兼容性
  11. golang中的URL 的编码和解码(转)
  12. 生物信息学|基于多尺度特征融合的药物-药物相互作用预测
  13. 探讨:Mac真的有必要安装双系统吗
  14. 时隔一年半,我,一个卑微的前端初学者,又来写面经了
  15. 利用MATLAB免费生成GIF
  16. 【逻辑题】头花是什么颜色
  17. HP-UX Samba服务配置手册
  18. 爱普生Epson PictureMate 240 打印机驱动
  19. python yolov5 脚本制作(第一部分:环境搭建、yolov5源码、权重文件获取、pycharm配置、pytorch下载、初次运行yolov5代码)
  20. 锂离子电池健康状态估计简介(一):基于Python的数据处理计算SOH,RUL,CCCT,CVCT

热门文章

  1. 制作好的app需要服务器吗,在直播app制作过程中,服务器是如何配置的?
  2. 计算机一级b必背知识点,全国计算机等级考试B经典必考资料_知识点总结.doc
  3. 【ICPC 2021网络赛2】The 2021 ICPC Asia Regionals Online Contest (II)签到题5题
  4. 家庭安防监控设备搭建
  5. 【POJ3349】Snowflake Snow Snowflakes(哈希表判重,维护一个集合)
  6. 虚拟机服务器配置毕业论文,基于Vmware的服务器虚拟化管理-毕业论文.doc
  7. linux限制堆栈大小,进程超过RedHat Enterprise Linux 6的线程堆栈大小限制?
  8. 高德定位html,Ionic3 高德Web定位
  9. bzoj 2916: [Poi1997]Monochromatic Triangles(推理)
  10. self.modules() 和 self.children()的区别