秒懂OnMeasure

自定义View之onMeasure() 可以说重载onMeasure(),onLayout(),onDraw()三个函数构建了自定义View的外观形象。再加上onTouchEvent()等重载视图的行为,可以构建任何我们需要的可感知到的自定义View。 本节我们探索自定义View中onMeasure()起到了什么样的作用,题外要插的一句是,Activity框架,View框架中大量的on函数基本上都应用到了Template模式,掌握这一 阅读详情

自定义控件系列:
秒懂OnMeasure
秒懂OnLayout
让自定义ViewGroup里的子控件支持Margin
让自定义ViewGroup支持Padding
自定义ViewGroup的一个综合实践 FlowLayout
onDraw
最简单的自定义View:SwitchView

我感觉之所以写不好自定义view,是因为我们了解的自定义View的基础知识知道的太少,但是在了解自定义view的基础知识的过程中,又很容易被源码带跑偏,找不到重点,结果是看了很多源码,云里雾里等于没看。

很多时候,源码是很重要,但是不懂适可而止的看源码,你就陷入了汪洋大海。
例如:初中几何里老师讲了“两点之间、直线最短”这个公理后,我们就可以做很多几何题目了,做的过程中还很爽,但是老师没讲“两点之间、直线最短”这个公理的源码是什么,为什么“两点之间、直线最短”,你要想证明这个公理,对于初中生甚至大学生都是不可能解答的,但是这丝毫不影响一个初中生做几何题目(当然,我记得老师说过,公理不需要证明)

所以这个系列博客采用知识点+应用的模式,有重点,有举例

当这些结论性的知识点积累到足够多,很多自定义view,不过就是多个结论的综合应用+小小逻辑算法,我们怕的不是小小逻辑算法,再绕的算法,多试验就出来了,但是不懂基本的结论性知识点,就很茫然了

知识点

关于MeasureSpec是什么,不懂的朋友请先搜索一下,这里对这个不做解释。

  1. 如果你的自定义view的宽高只支持MeasureSpec.EXACTLY(即:match_parent和具体的数值),那么onMeasure方法不需要重写,因为View这个基类已经默认实现了

  2. 如果你想支持MeasureSpec.AT_MOST(即:wrap_content),必须重写onMeasure方法,不然你写wrap_content和match_parent效果是一样的(即系统默认返回一个父容器所能给予你的最大尺寸)。

    想想为什么,View这个基类,不帮我们实现MeasureSpec.AT_MOST模式呢?
    因为不同的view,对于自己的MeasureSpec.AT_MOST(包裹内容)有自己特有的计算方式,例如:ImageView的MeasureSpec.AT_MOST,ImageView会根据你设置的图片,来计算在wrap_content时候的宽高。
    TextView的MeasureSpec.AT_MOST,TextView会根据你设置的文字内容多少,(因为内容多了可能换行)和你设置的TextSize(字体大了,自然需要更大的宽高)来计算Textview在wrap_content时候的宽高
    FrameLayout在MeasureSpec.AT_MOST模式下,宽度就是所有子view里面最大的那个View的宽度,高度就是所有子view里的最大的那个View的高度
    LinearLayout在MeasureSpec.AT_MOST模式下(假设是竖向布局),宽度是所有View里最大的那个View的宽度,高度是所有View的高度的总和
    所以View天生支持MeasureSpec.EXACTLY,但是他对于MeasureSpec.AT_MOST是无能为力的,需要具体的View自己具体实现

  3. 最重要就是这个方法,计算出控件在各种模式下的宽高,通过这个方法设置进去,就好了setMeasuredDimension(width, height);

以下就是View的onMeasure的默认实现(源码)

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
    
 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://关键在这里系统对AT_MOST和EXACTLY的处理是一样的,
        //都是返回父容器的最大尺寸,不信你可以自己打印出来看看
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

应用

1. 给出支持MeasureSpec.AT_MOST的模板代码

其实这个代码是套路代码,结构是不变的

当写wrap_content,意思是父布局不传给你确定的尺寸,需要这个view自己确定个默认的尺寸,这个尺寸是你自己根据自己的情况计算出来的。

public class CustomView extends View {


    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 首先计算一下在AtMost模式下,这个自定义view的宽高,
        // 这里把计算出来的宽高封装在了一个Point里,x为宽,y为高
        // 这是模板代码,你只需要按照自己的实现caculateAtMostSize()的具体逻辑,其余的不用变
                Point point = caculateAtMostSize(widthMeasureSpec,heightMeasureSpec);


        // 根据 默认宽高、AtMost下的宽高、MeasureSpec测量规格,计算出最终这个view的宽高
        int width = measureSize(0, point.x, widthMeasureSpec);
        int height = measureSize(0, point.y, heightMeasureSpec);

        // 把上面计算出来的宽高作为参数设置给setMeasuredDimension就ok了
        setMeasuredDimension(width, height);
    }


    /**
     * 通过widthMeasureSpec计算出这个View最终的宽高
     *
     * @param defalut     这个view的默认值,仅仅是为了支持下UNSPECIFIED模式,但是这个模式其实用不到
     * @param atMostSize  AT_MOST下的尺寸
     * @param measureSpec 测量规格(包含了模式+尺寸)
     * @return
     */
    private int measureSize(int defalut, int atMostSize, int measureSpec) {


        int result = defalut;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
                result = defalut;
                break;
            case MeasureSpec.AT_MOST:
                //在AT_MOST模式下,系统传来的specSize是一个父容器所能容纳的最大值,你这个自定义view计算的尺寸不能大于这个值
                result = Math.min(atMostSize, specSize);
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
        }


        return result;
    }


    /**
     * 计算本View在AtMost模式下的宽高
     * 其他代码都是不用动的,在这里写下你特有的逻辑就可以
     * 我这里只是简单的返回宽高都是 200
     *
     * @return
     */
        private Point caculateAtMostSize(int widthMeasureSpec, int heightMeasureSpec) {
        //一般情况,写的自定义view是不需要特别计算这个值的,我会直接给一个默认值
        //但是你是自定义ViewGroup的话,这里你必须好好写了
        int width = 200;
        int height = 200;
        return new Point(width, height);
    }











2. 一个自定义ViewGroup支持MeasureSpec.AT_MOST的例子:

效果如图:
在这里插入图片描述

对应的布局文件时这样的
在这里插入图片描述
注意:这里仅仅写支持AT_MOST的代码,还没写onLayout,所以代码运行是看不到效果的,可以打印log,来看下这个view的宽高是不是正确的

/**
     * 计算本View在AtMost模式下的宽高
     * 其他代码都是不用动的,在这里写下你特有的逻辑就可以
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     * @return
     */
    private Point caculateAtMostSize(int widthMeasureSpec, int heightMeasureSpec) {

        int width = 0;
        int height = 0;

        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            // 测量一下子控件的宽高
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            // 获得子控件的宽高
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            // 因为我们的自定义View模拟的是竖向的LinearLayout,所以:
            // 控件的宽度为所有子控件里,宽度最大的那个view的宽度,
            // 控件高度是所有子空间的高度之和
            width = Math.max(childWidth, width);
            height += childHeight;
        }


        return new Point(width, height);
    }

本例源码github之CustomView

参考资料:
《Android群英传》

通过FrameLayout分析onMeasure 阅读详情

相关推荐

基于PCA的故障诊断方法(matlab)

1. PCA原理分析 PCA的原理主要是将原始数据进行降维。其具体工作原理参照:CodingLabs - PCA的数学原理 2. 数据预处理 训练数据集(只有正样本)为维数据,即有n个采样值,每个采样值有m个特征。 2.1 数据归一化 将数据X针对每个特征归一化为均值为0,均方根为1的数据。 其中: 3. PCA降维 3.1 首先求取协方差矩阵 协方差矩阵的公式为: 计算出来的协方差矩阵为特征m*m维矩阵。 3.2 求取特征值和特征向量 求取协方差矩阵R的特征值.

tangxianyu的博客 1万+

android 测试界面大小,Android view的测量及绘制

view的测量:首先需要知道的是view的三种测量模式:1、EXACTLY:精确值模式,当我们对view的layout_width和layout_height属性指定具体的数值的时候,比如layout_width=“100dp”或者指定为match_parent时,系统进行测量的时候,使用的是这种模式。2、AT_MOST:最大值模式,当我们对view的layout_width和layout_hei...

weixin_34563472的博客 348

地理空间坐标系统-不同椭球基准间的坐标转换

基于同一个椭球基准,可以构建三类地理空间坐标系:大地球面坐标系、大地空间直角坐标系、大地投影坐标系。由于坐标原点和椭球长短半径等都相同,这三类坐标系之间可以通过无损的数学方法相互之间进行转换。那么现在问题来了,不同椭球基准(在全球范围来看存在成百上千的椭球基准)之间的坐标怎么转换?比如,北京54、西安80、国家2000,特别是在我国,现在主推国家2000坐标系,那么如何将历史的测绘成果(北京54和...

技术改变世界 8336

自定义View之 onMeasure() view的高度自适应wrap_content view的测量

在很多自定义view之后,控件的高度需要自适应,即使使用wrap_content没有作用还是match_parent的效果,这时就需要重写onMeasure()方法来实现,view类的onMeasure()方法默认是只支持.EXACTLY模式,所以在自定义view先支持wrap_content就得重写onMeasure(),在这里就需要说一下测量的三种模式了: 第一种: EXACTCLY 大

mxiaoyem的博客 1万+

VBA一键汇总多个工作簿-名称相同的工作表-的指定区域数据

VBA一键汇总多个工作簿-名称相同的工作表-的指定区域数据 日常工作,我们经常需要汇总相同格式的工作簿的某个工作表的数据 如1月业绩、2月业绩。。。。12月业绩等 姓名 数量 数据22 22 数据23 23 数据24 24 数据25 25 数据26 26 数据27 27 数据28 28 数据29 29 数据30 30 数据31 31 数据32 32 数据33 33 数据34

陈表达的博客 5983

ETL第八章无人售货机零售项目实践

ETL实战项目——无人售货机

m0_52058217的博客 4418

关于UNSPECIFIED、AT_MOST、EXACTLY和关于onmeasure两次调用

1. wrap--AT_MOST fill--EXACTLY 固定值--EXACTLY 上边是大家都知道的,但是一直很疑惑UNSPECIFIED什么情况发生,今天测了下,发现在使用weigt时会调用,因为此时定义的值为0dp,这不就是UNSPECIFIED嘛! 2.关于onmeasure两次调用 第一次应该是通过xml的设置进行计算 ps:UNSPECIFIED时第一轮的on

首席科学家的专栏 3810

基于微信小程序的扫码签到系统源码

大等于jdk1.8,大于mysql5.5,idea(eclipse),微信开发者工具。代码注释齐全,没有多余代码,适合学习(毕设),二次开发,包含论文技术相关文档。签到管理:新增签到,点击查看码展示二维码(有时效性)springboot mybatis 小程序。签到管理:查看用户创建的签到,可删除。用户管理:查看注册用户信息,及删除。签到记录:查看用户签到记录:可删除。个人信息:展示个人信息,可修改。统计分析:查看用户,签到数量。签到记录:查看用户签到记录。登录注册(含授权登录)我的签到:查看签到记录。

wfuhui的博客 5224

android中对View的onMeasure()方法的理解

在android开发中,很多人对自定义View是望而生畏,我也一样,但这又是向高级进阶的必经之路,主要是对View里面的很多方法不知道怎么理解,其中一个就是onMeasure()方法,网上有很多这样解释说明,可能是由于我的领悟力有限,一直没能搞明白,今天有点空,好好研究一下,并记录下来,也希望对大家有所帮助。 首先,我自定义一个MyView,继承于View,onMeasure()方法不做处理,直接

谁与争锋的专栏 3万+

NBIS单细胞教程:差异基因(五)

此文章是通过学习瑞典国家生物信息学基础设施(NBIS) 所开放的单细胞分析教程加上网上所查找的资料,自身的理解所形成的,可能会有不足之处。该部分是对不同集群之间的差异基因进行分析。参考来源:https://github.com/NBISweden/workshop-scRNAseq/blob/master/labs/seurat/seurat_05_dge.Rmd感兴趣的话可以阅读原文。

songyi10的博客 1万+

第4篇:使用 NModbus 库快速搭建 Modbus TCP 通信(从零开始用 C# 开发 Modbus 上位机)

本文介绍了如何使用 NModbus 库快速搭建 Modbus TCP 上位机通信程序。通过安装 NModbus4 NuGet 包,开发者可以轻松实现 Modbus TCP 连接,无需手动处理底层协议细节。文章详细演示了核心功能实现: 创建 TCP 客户端连接设备 读取保持寄存器(功能码0x03) 写入单个寄存器(功能码0x06) 关闭连接释放资源 提供完整C#示例代码,包含初始化连接、数据读写等关键操作,帮助开发者快速构建Modbus TCP通信应用。相比手动实现,NModbus库大幅简化了开发流程,特别适

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1047

自定义控件--onMeasure三种测量方式以及和子控件的关系

网上的资料总是会有很多的模糊性和不定性,另外对细节的讲解也不到位,导致会经常看到这个人这样写,那个人那样写,然后还有这个人这样讲那个人又是另一种讲法,最终导致自己会发晕。如果说网上讲解的内容总是变化的话不妨自己整理一下,将重点全部挑出来,然后注意细节,反复理解,再将自己理解的东西给写下来,然后再重新总结理解,那样就不会被网上的资料带偏学的迷迷糊糊的了。另外这篇也是我学习过程中自己的理解和感悟,如果有说的不对的地方还请各位能够指正。over。

m0_46606613的博客 684

YOLO26涨点改进 | 全网独家,注意力创新改进篇 | Arxiv2025 | YOLO26引入MSLA多尺度线性注意力模块,高效提取多尺度特征和建模长程依赖,含多种创新改进,助力有效涨点

本文提出了一种多尺度线性注意力模块(MSLA)来优化YOLO26模型。MSLA通过并行使用不同尺寸的深度可分离卷积(3×3至9×9)提取多尺度特征,并结合线性注意力机制高效建模全局依赖关系。该模块显著提升了模型对多尺度目标的检测能力,同时保持了轻量化特性。实验表明,MSLA能有效增强小目标检测和复杂场景下的分割精度。文章详细介绍了MSLA的网络结构、核心优势及实现代码,并提供了两种集成MSLA的YOLO26改进方案,为实时目标检测任务提供了高效解决方案。

Ai缝合怪、助力小伙伴高效发论文 304

Android View绘制onMeasure流程

onMeasure()方法的作用就是测量View需要多大的空间,就是宽和高。大家可能会有这样的疑问。就是我在xml文件中已经指定好了某个View宽高尺寸了,那么自定义View时不就没有必要再次获取宽高并设置宽高吗?onMeasure方法不就没有了吗?其实不然,我们就知道,在xml布局文件中,我们的layout_width和layout_height参数可以不用写具体的尺寸,而是wrap_content或者是match_parent。

weixin_43700867的博客 1385

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

03. onMeasure介绍

简书:http://www.jianshu.com/u/92a2412be53e邮箱:934137388@qq.com掘金:https://juejin.im/user/499639464759898泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?

qq_35829566的博客 964

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

LinearLayout onMeasure源码阅读

onMeasure()方法解读 measureWithLargestChild 作用 : 该属性为true的时候, 所有带权重的子元素都会具有最大子元素的最小尺寸; 且只有当父view布局方向上的宽度或高度为wrap_content才有效登录后复制 @Override protected void onMeasu...

weixin_37046340的博客 112

Android onMeasure过程分析

其实本来一次就可以了,但是,performTraversals 这一段代码,判断出来Configuration 变化了,导致updatedConfiguration = true, 然后 // If the pending {@link MergedConfiguration} handed back from // {@link ...

男儿不展风云志,空有天生八尺躯 890

onMeasure()、onLayout()

前言:   自定义控件的三大方法: 测量: onMeasure(): 测量自己的大小,为正式布局提供建议 布局: onLayout(): 使用layout()函数对所有子控件布局 绘制: onDraw(): 根据布局的位置绘图 onDraw() 里面是绘制的操作,可以看下其他的文章,下面来了解onMeasure()和onLayout()方法。 一、o...

疾风剑豪 1379

Android onMeasure()测量流程解析

Android onMeasure()测量流程解析 文章目录Android onMeasure()测量流程解析前言组件测量的那些结论一、MeasureSpec:测量规则二、查看测量流程源码2.1 查看ViewRootImpl的PerformTraveals()方法2.2 View类的默认onMeasure()方法2.3 从FrameLayout的onMeasure()方法了解自定义ViewGroup的测量行为 前言 众所周知,Android 中组件显示到屏幕上需要经历测量、布局、绘制三个阶段,我们

weixin_43864176的博客 1890

关于定义布局OnMeasure 的总结

: measure过程分析 因为DecorView实际上是派生自FrameLayout的类,也即一个ViewGroup实例,该ViewGroup内部的ContentViews又是一个ViewGroup实例,依次内嵌View或ViewGroup形成一个View树。所以measure函数的作用是为整个View树计算实际的大小,设置每个View对象的布局大小(“窗口”大小)。实际对应属性

u013598111的专栏 549

自定义ViewGroup为什么要重写onMeasure方法

为什么要重写onMeasure方法

qq_44874625的博客 452

【Android】自定义view之onMeasure

1 onMeasure什么时候会被调用 onMeasure方法的作用是测量控件的大小,当我们创建一个View(执行构造方法)的时候不需要测量控件的大小,只有将这个view放入一个容器(父控件)中的时候才需要测量,而这个测量方法就是父控件唤起调用的。当控件的父控件要放置该控件的时候,父控件会调用子控件的onMeasure方法询问子控件:“你有多大的尺寸,我要给你多大的地方才能容纳你?”,然后传入两个参数(widthMeasureSpec和heightMeasureSpec),这两个参数就是父控件告诉子控件可获

sinat_36955332的博客 1863

onMeasure实例分析

上面这个两个视图是Android API中没有给出来的但在来电接听和闹钟被使用到的一个widget视图——GlowPadView.java 我们通过源码来看看这个View的大小是怎么通过onMeasure来控制的。 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

u012604322的专栏 2763

Android的onMeasure方法

在Android开发中,当Android原生控件不能满足我们的需求的时候,就需要自定义View。View在屏幕上绘制出来先要经过measure(计算)和layout(布局)。   什么时候调用onMeasure方法?   当子View的父控件要放置该View的时候,父控件会传递两个参数给View——widthMeasureSpec和heightMeasureSpec。这两个参数是Vie

青春的光与影 1635

简单理解View的onMeasure过程

View的绘制需要经过Measure、Layout、Draw这三个流程。很多朋友在自定义View的时候,特别是对Measure过程不能十分理解,这里结合Android的一些源码和资料来简单说明。   首先来看一下View的measure方法:   public final void measure(int widthMeasureSpec, int heightMeasureSpec) {

lovejavasman的博客 2015

理解onMeasure

Android系统调用onMeasure来定义view的大小,很长时间理解不是很透彻,今天花了些时间打日志来理解它。总结如下。         1. widthMeasureSpec和heightMeasureSpec这两个值是android:layout_width="200dp" android:layout_height="80dp"来定义的,它由两部分构成,可通过int specMode

hjj0212的专栏 1万+
上一篇: 热修复原理浅析(二)
下一篇: 秒懂OnLayout
Android_Study_OK
博客等级 码龄11年 91粉丝 128原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值