Android 自定义 View Measure 过程

本贴最后更新于 2832 天前,其中的信息可能已经沧海桑田

子 View 的测量模式和大小请看下表:

Paste_Image.png

规律总结:(以子 View 为标准,横向观察)

  • 当子 View 采用具体数值(dp / px)时
    无论父容器的测量模式是什么,子 View 的测量模式都是 EXACTLY 且大小等于设置的具体数值;
  • 当子 View 采用 match_parent 时
    • 子 View 的测量模式与父容器的测量模式一致
    • 若测量模式为 EXACTLY,则子 View 的大小为父容器的剩余空间;若测量模式为 AT_MOST,则子 View 的大小不超过父容器的剩余空间
  • 当子 View 采用 wrap_parent 时
    无论父容器的测量模式是什么,子 View 的测量模式都是 AT_MOST 且大小不超过父容器的剩余空间。

UNSPECIFIED 模式:由于适用于系统内部多次 measure 情况,很少用到,故此处不讨论

问题描述
在使用自定义 View 时,View 宽 / 高的 wrap_content 属性不起自身应有的作用,而且是起到与 match_parent 相同作用。
问题分析
问题出现在 View 的宽 / 高设置,那我们直接来看自定义 View 绘制中第一步对 View 宽 / 高设置的过程:measure 过程中的 onMeasure() 方法

onMeasure()

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //参数说明:View的宽 / 高测量规格 //setMeasuredDimension() 用于获得View宽/高的测量值 //这两个参数是通过getDefaultSize()获得的 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }

继续往下看 getDefaultSize()

getDefaultSize()

  • 作用:根据 View 宽/高的测量规格计算 View 的宽/高值
  • 源码分析如下:
public static int getDefaultSize(int size, int measureSpec) { //参数说明: // 第一个参数size:提供的默认大小 // 第二个参数:宽/高的测量规格(含模式 & 测量大小) //设置默认大小 int result = size; //获取宽/高测量规格的模式 & 测量大小 int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { // 模式为UNSPECIFIED时,使用提供的默认大小 // 即第一个参数:size case MeasureSpec.UNSPECIFIED: result = size; break; // 模式为AT_MOST,EXACTLY时,使用View测量后的宽/高值 // 即measureSpec中的specSize case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } //返回View的宽/高值 return result; }

从上面发现:

  • getDefaultSize() 的默认实现中,当 View 的测量模式是 AT_MOST 或 EXACTLY 时,View 的大小都会被设置成子 View MeasureSpec 的 specSize。
  • 因为 AT_MOST 对应 wrap_content;EXACTLY 对应 match_parent,所以,默认情况下,wrap_contentmatch_parent 是具有相同的效果的。

解决方案:
当自定义 View 的布局参数设置成 wrap_content 时时,指定一个默认大小(宽 / 高)。

具体是在复写 onMeasure() 里进行设置

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 获取宽-测量规则的模式和大小 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); // 获取高-测量规则的模式和大小 int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); // 设置wrap_content的默认宽 / 高值 // 默认宽/高的设定并无固定依据,根据需要灵活设置 // 类似TextView,ImageView等针对wrap_content均在onMeasure()对设置默认宽 / 高值有特殊处理, //具体读者可以自行查看 int mWidth = 400; int mHeight = 400; // 当布局参数设置为wrap_content时,设置默认值 if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT && getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) { setMeasuredDimension(mWidth, mHeight); // 宽 / 高任意一个布局参数为= wrap_content时,都设置默认值 } else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) { setMeasuredDimension(mWidth, heightSize); } else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) { setMeasuredDimension(widthSize, mHeight); }

这样,当你的自定义 View 的宽 / 高设置成 wrap_content 属性时就会生效了。

  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    335 引用 • 324 回帖 • 1 关注
  • View
    11 引用 • 2 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • jsDelivr

    jsDelivr 是一个开源的 CDN 服务,可为 npm 包、GitHub 仓库提供免费、快速并且可靠的全球 CDN 加速服务。

    5 引用 • 31 回帖 • 94 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 500 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 443 关注
  • 反馈

    Communication channel for makers and users.

    126 引用 • 929 回帖 • 266 关注
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 788 关注
  • OpenCV
    15 引用 • 36 回帖 • 1 关注
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    226 引用 • 476 回帖
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 1 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 382 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    20 引用 • 37 回帖 • 570 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 83 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    946 引用 • 1460 回帖
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 176 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    53 引用 • 40 回帖
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 207 关注
  • Hibernate

    Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。

    39 引用 • 103 回帖 • 719 关注
  • Visio
    1 引用 • 2 回帖
  • danl
    162 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    21 引用 • 204 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 1 关注
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖 • 6 关注
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    198 引用 • 541 回帖 • 2 关注
  • Word
    13 引用 • 40 回帖
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3455 回帖 • 165 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 278 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖