调用view.measure(0,0)时发生了什么

View.measure(0, 0)方法什么情况下能正确计算宽高 1.问题 在最新的需求中,想通过getMeasureWidth( )方法获取一个FrameLayout布局的measureWidth值,但由于未进行Measure步骤,所以getMeasureWidth( )最终会返回0。所以想手动调用View.measure(0, 0)方法,主动触发Measure步骤。再获取measureWidth。但该方案对一些View是无效的。下面分析在什么情况下执行me... 阅读详情

在 Activity 的 onCreate、onStart、OnResume 生命周期中,无法直接得到 View 的宽高信息。
网上有以下几种常见的解决办法:

  1. 在 Activity#onWindowFocusChanged 回调中获取宽高。
  2. view.post(runnable),在 runnable 中获取宽高。
  3. ViewTreeObserver 添加 OnGlobalLayoutListener,在 onGlobalLayout 回调中获取宽高。
  4. 调用 view.measure(),再通过 getMeasuredWidth 和 getMeasuredHeight 获取宽高。

其中第四种方法,网上有很多直接传递两个0的写法,即 view.measure(0,0).
接下来会分析传递的两个0在程序内部发生了些什么,为什么调用之后就能获取 View 的宽高?

  • 了解 MeasureSpec
    measure(int widthMeasureSpec,int heightMeasureSpec) 的参数是两个符合 MeasureSpec 规范的 int 值。
    MeasureSpec 代表一个32位的 int 值,高2位代表 SpecMode,低30位代表 SpecSize.
  • SpecMode
    测量模式,有以下三类。

UNSPECIFIED
EXACTLY
AT_MOST

  • SpecSize
    对应测量模式下规格的大小。

  • 生成 MeasureSpec
    一组 SpecMode 和 SpecSize 可以打包成一个 MeasureSpec:

public static int makeMeasureSpec(int size, int mode) {
    if (sUseBrokenMakeMeasureSpec) {
        return size + mode;
    } else {
        return (size & ~MODE_MASK) | (mode & MODE_MASK);
    }
}
  • 获取 SpecMode 和 SpecSize
    一个 MeasureSpec 同样可以解包为一组 SpecMode 和 SpecSize:
public static int getMode(int measureSpec) {
    return (measureSpec & MODE_MASK);
}
public static int getSize(int measureSpec) {
    return (measureSpec & ~MODE_MASK);
}
  • 0所对应的 MeasureSpec
    现在知道了传递的0并不是简单的一个0,它符合着 MeasureSpec 规范。
    将0解包后,所对应的 SpecMode = 0,SpecSize = 0.
    SpecMode 0 对应的模式为 UNSPECIFIED.
    UNSPECIFIED的官方解释:

The parent has not imposed any constraint on the child. It can be whatever size it wants.
父容器不会对子元素加以任何约束,子元素可以是任何大小。

  • 创建一个简单的项目
//MainActivity.java 部分代码
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imgView = (ImageView) findViewById(R.id.imgView);
        imgView.measure(0, 0);

        Log.i(TAG, "imageView MeasuredWidth = " + imgView.getMeasuredWidth());
        Log.i(TAG, "imageView MeasuredHeight = " + imgView.getMeasuredHeight());
    }
<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main.xml -->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <com.gujin.measure_demo.LogImageView
        android:id="@+id/imgView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@mipmap/ic_launcher"/>
</LinearLayout>
//LogImageView.java 部分代码
public class LogImageView extends ImageView {
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMeasureSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMeasureSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);

        Log.i(TAG, "widthMeasureSize = " + widthMeasureSize);
        Log.i(TAG, "widthMeasureMode = " + widthMeasureMode);
        Log.i(TAG, "heightMeasureSize = " + heightMeasureSize);
        Log.i(TAG, "heightMeasureMode = " + heightMeasureMode);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
  • 代码分析
    有了项目以后,在 LogImageView#onMeasure()#super.onMeasure() 处打上断点。
    观察调用栈:

     

    调用栈

     

    从调用栈中可以看到当调用 imgView.measure(0, 0) 时,执行了继承自父类 View 的 measure 方法,measure 方法中调用了 LogImageView 重写过的 onMeasure 方法,打印log如下:

I/LogImageView: widthMeasureSize = 0
I/LogImageView: widthMeasureMode = 0
I/LogImageView: heightMeasureSize = 0
I/LogImageView: heightMeasureMode = 0

接着会执行 super.onMeasure,在 ImageView 的 onMeasure 中进行实际的测量。
ImageView 的 onMeasure 方法比较长,进行了删减,只描述一下大概逻辑:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int w; //宽
    int h; //高

    w = mDrawableWidth;
    h = mDrawableHeight;

    int widthSize;
    int heightSize;

    w = Math.max(w, getSuggestedMinimumWidth());
    h = Math.max(h, getSuggestedMinimumHeight());

    widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
    heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);

    setMeasuredDimension(widthSize, heightSize);
}

首先让宽高等于 ImageView 中 Drawable 的宽高,接着调用 getSuggestedMinimumWidth/Height 方法取较大值重新赋给宽高。

  • 分析 getSuggestedMinimumWidth:
protected int getSuggestedMinimumWidth() {
    return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}

如果 view 没有 background 则返回最小宽度,否则比较 view 的最小宽度和 background 的最小宽度返回较大值。
view 的最小宽度 MinWidth 就是在 xml 中定义 android:minWidth 的值,或者是通过调用 view.setMinimumWidth 设置的最小宽度。
getSuggestedMinimumHeight 方法同理。

然后通过 resolveSizeAndState 方法计算 widthSize 和 heightSize.

  • 分析 resolveSizeAndState:
public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
    final int specMode = View.MeasureSpec.getMode(measureSpec);
    final int specSize = View.MeasureSpec.getSize(measureSpec);
    final int result;
    switch (specMode) {
        case View.MeasureSpec.AT_MOST:
            if (specSize < size) {
                result = specSize | MEASURED_STATE_TOO_SMALL;
            } else {
                result = size;
            }
            break;
        case View.MeasureSpec.EXACTLY:
            result = specSize;
            break;
        case View.MeasureSpec.UNSPECIFIED:
        default:
            result = size;
     }
     return result | (childMeasuredState & MEASURED_STATE_MASK);
}

上面分析过,measure(0,0) 传递的0解包后对应的 SpecMode 为 UNSPECIFIED。
可以看到 specMode 为 UNSPECIFIED 时返回值 result 直接等于了 size,而在 EXACTLY 和 AT_MOST 情况中受到了 SpecSize 的影响,这也解释了官方定义中说 UNSPECIFIED 模式下父容器不会对子元素加以任何约束的原因。
函数结尾 result | (childMeasuredState & MEASURED_STATE_MASK),childMeasuredState 传递进来为0,和 MEASURED_STATE_MASK 与运算后结果为0,result 和0进行或运算保持不变。
所以最后的 return 值就是传递进来的 size。

最终调用父类 View 的 setMeasuredDimension 方法将计算出的 widthSize 和 heightSize 传递到 View 中。
至此 ImageView 的 onMeasure 方法分析完毕。
接下来在 View 内继续分析:

protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
    ...
    setMeasuredDimensionRaw(measuredWidth, measuredHeight);
}
private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
    mMeasuredWidth = measuredWidth;
    mMeasuredHeight = measuredHeight;

    mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
}

可以看到在 setMeasuredDimension 方法中参数最终传递给 setMeasuredDimensionRaw 方法。
在这里,经过一系列计算的 measuredWidth 和 measuredHeight 赋给了成员变量 mMeasuredWidth 和 mMeasuredHeight,然后将 mPrivateFlags 状态位设置为 PFLAG_MEASURED_DIMENSION_SET.
至此,调用 view.measure(0,0) 之后的计算得出的宽高值已经保存到成员变量中。

  • 取宽高
    现在调用 getMeasuredWidth/Height 方法就已经可以获得测量后的宽高。
public final int getMeasuredWidth() {
    return mMeasuredWidth & MEASURED_SIZE_MASK;
}

MEASURED_SIZE_MASK 的值为 0x00ffffff,和 mMeasuredWidth 进行与运算后,可以将 mMeasuredWidth 的高8位全置0,去掉其他信息。
但是上边说 MeasureSpec 中高2位为 SpecMode,其余30位为 SpecSize,为什么将高8位置0?
还记得 resolveSizeAndState 方法么:

public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
...
switch (specMode) {
    case View.MeasureSpec.AT_MOST:
        if (specSize < size) {
            result = specSize | MEASURED_STATE_TOO_SMALL;
        }
        ...
        break;
   ...
   }
}

specSize 和 MEASURED_STATE_TOO_SMALL 进行了或运算,MEASURED_STATE_TOO_SMALL 的值为 0x01000000.
也就是说 SpecSize 的高6位(MeasureSpec 的高3~8位)会记录 STATE 信息,所以要将高8位全置0。
最终在 Log 中可以看到取出的宽高值:

I/MainActivity: imageView MeasuredWidth = 144
I/MainActivity: imageView MeasuredHeight = 144



作者:sunrain_
链接:https://www.jianshu.com/p/dbd6afb2c890
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Android View measure(0,0)的作用 将view.measure(0,0)设置为0的时候表示,此时不需要考虑父控件的布局问题,直接使用getMeasuredWidth和getMeasuredHeight获取此view的自身的实际大小,可以看下面的例子:这个是在网上引用的一段代码 1 2 3 4 5 6 7 8 9 10 11 12 13 阅读详情

相关推荐

LSTM cell结构的理解和计算

LSTM是传统RNN网络的扩展,其核心结构是其cell单元,网上LSTM的相关资料繁多,质量参差不齐,下面主要结合LSTM神经网络的详细推导和 Christopher Olah的blog两篇文章中的内容进行说明。主要介绍网络如何计算,为何这么算先不展开:)。前者一副图加上29个公式,简洁明了;后者娓娓道来,适合初学者。首先是LSTM cell最常见的结构图: 这是变形的版本(找不到更清晰的版本了),

songhk0209的博客 2万+

measure(0,0)方法的浅谈

View view = View.inflate(getContext(), R.layout.header_view,null); ImageView iv = (ImageView) view.findViewById(R.id.iv); final LinearLayout.LayoutParams layoutParams = (LinearLayout.

qq_28192929的博客 639

IPD的分析工具与模型(十六)CBB公用基础模块管理实现资源共享,缩短开发周期降低成本

CBB流程的开发环节,基于CBB规划中所识别和设计的CBB,进行CBB的详细设计(包括参数设计和接口设计),并最终实现CBB的落地开发。作为特殊类型的技术构件,CBB的开发流程,可沿用技术开发中的构件开发流程,具体包括概念、计划、开发和迁移等步骤,具体可参见前文的相关介绍。有了蓝图与架构设计,落地实施是关键攻坚。具体工作内容包括:具体工作内容包括:a. 以相似性、聚类、相对独行性、可组合、可扩展性、可维护性等原则为指导,按照产品的功能特征和业务类型,聚焦零散的功能点,形成功能模块,实现产品功能模块的划分;

Easyways1的博客 1377

Measure(0,0)到底发生了什么

最开始接触这个方法的时候是在写自定义控件的时候,比如,父控件的高度需要根据子控件来动态改变,那么我们就需要手动的去测量每一个子控件,然后他们的总高度就是父类最终的高度了。 在大多数情况下,这个逻辑可能是能够走通的,但是,我会举个栗子来让这个逻辑走不通。 1. 如果我对一个原生的View使用measure(0,0),是毫无意义的。 protected void onMeasure(in

Wood_Water_Peng的博客 3608

提示词工程的几个参数

低 temperature + 低 top-p:输出最稳定、最可靠,适合需要准确性和一致性的场景。高 temperature + 高 top-p:输出最多样化、最富有创意,适合需要灵感和探索的场景。Max Length:您可以通过调整max length来控制大模型生成的 token 数。指定 Max Length 有助于防止大模型生成冗长或不相关的响应并控制成本。是一个字符串,可以阻止模型生成 token,指定是控制大模型响应长度和结构的另一种方法。例如,您可以通过添加 “11” 作为。

weixin_44212787的博客 1826

Qt代码-软件商店

ui->statusBar->showMessage(QString("%1 已卸载").arg(app["name"].toString()));ui->statusBar->showMessage(QString("开始下载 %1...").arg(app["name"].toString()));QString("%1 已下载完成,是否立即安装?ui->statusBar->showMessage(QString("%1 下载完成").arg(app["name"].toString()));

寒寒豆豆软件公司的博客 110

view.measure(0,0)使用的原理

调用view.measure(0,0)时发生了什么 view.measure(0,0) Determining the size of an Android view at runtime getmeasuredheight() and getmeasuredwidth() returns 0 after View.measure()

“点点”专栏 445

YOLO系列专栏(六):YOLO26热力图可视化 | 解析模型推理逻辑,定位检测关键区域

YOLO26作为新一代目标检测模型,其核心优势是高效的特征提取和精准的目标定位,但模型内部的推理过程的“黑盒”特性,给我们的优化带来了很大困扰:❌ 检测精度低:不知道是模型没学到关键特征,还是特征提取不充分;❌ 出现误检/漏检:无法定位问题根源——是锚框不合适?还是特征图未捕捉到目标?❌ 模型优化盲目:调参、修改网络结构全靠“猜”,缺乏针对性;❌ 难以解释模型行为:实际项目中,需要说明模型“为什么检测到这个目标”,尤其是医疗、工业等对可解释性要求高的场景。而热力图可视化。

qq_36130719的博客 730

带着问题学习Android中View的measure测量

在进行研究measure原理之前,我们先带着这三个问题来想想。因为我是遇到这三个问题才开始研究measure的源码,所以我也把下面的三个问题当做引子。 调用measure(int widthMeasureSpec, int heightMeasureSpec)方法传递的参数是什么? 为什么调用measure方法View控件没有进行测量? 如何强制view进行测量? 在进行研究之前,我们先来看一个简单

钝悟需要时间的打磨,顿悟需要时间的积累 5817

SAP GUI 字段遮罩功能详解及实现

默认情况下,系统使用作为掩码模式,遮罩整个字段内容长度;对于货币金额类型,掩码后会保留小数位并在整数位部分全部显示为,如****.**若需自定义掩码模式,可利用以下方式:维护“Maintain Masking Pattern”节点,在其中定义新的掩码方式(如:只露出后四位,其他位以X替代等);实现 BAdI(或类似命名,具体以系统版本为准)的方法,通过 ABAP 代码读取原始值,并依据业务逻辑生成掩码字符串返回,动态替换界面输出值;

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 707

AI Agent开发第82课-手把手教你把paddleocr-vl做成mcp使其在DIFY里运行

本文详解如何将国产顶尖多模态 OCR 模型 PaddleOCR-VL 封装为标准 MCP(Model Calling Protocol)服务,并通过自研的 HTTP-based MCP Client 接入 Dify 1.10,实现 AI Agent 在对话中自动识别并调用 OCR 能力。该方案已在某头部保险公司真实业务流程中落地,使用了当前最先进的“Agentic AI 原生”设计思想。

打造全国最全的AI Agent开发知识领域的博客 1624

android中View.measure方法详解

View 源码路径 frameworks\base\core\java\android\view\View.java 源码中国链接:http://www.oschina.net/code/explore/android-2.2-froyo/android/view/View.java [java] view plaincopy public 

lixiangers的专栏 638

​非线性分析-增加位移量可能出现下面错误。虽然求解无法在所有时间点完成,但在某些点上仍能够求解部分结果。请参阅“帮助系统”中的故障排除,以了解更多信息详情。由于受约束,规划求解引擎无法收敛

基于收敛状态拆分载荷步‌:在已收敛的载荷步基础上,将未收敛的关键区域拆分为更细的子步,比如在载荷突变点前设置5~10个子步,逐步加载。替换冲突约束为弱约束‌:若存在约束冲突,将刚性约束替换为弱弹簧约束(刚度设为1e-6~1e-4),既限制刚体位移,又不影响结构的变形自由度,命令流:SPRING, NODE, K, 1e-6。部分区域约束完整,但存在未被约束的刚体自由度,或约束类型与大变形/接触逻辑冲突,比如某部件的位移约束在初始阶段有效,但大变形后约束位置脱离实际受力点,导致求解器在该阶段无法收敛。

qq_15963745的博客 143

Measure(0,0)的探讨

最近研究自定义view,遇到一个问题,在自定义ViewGroup的时候经常会在父view的onMeasure方法中调用如下代码去测量子view的宽高: @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //测量ViewGroup本身的宽高,由于没有wrap_co

wangjima32的博客 825

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

【Android】浅谈View绘制流程

measureSpec是一个int类型,在java占32字节,其1~30位表示实际测量长度,31~32位即测量模式通过MODE_MASK获得mode,MODE_MASK 即。

qq_40900926的博客 910

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Android中的View

一.Android屏幕元素层次结构 1.android.app.Activity 对于一个Android应用来说,android.app.Activity类实例是一个最基本的功能单元。一个Activity实例可以做很多的事情,但是它本身无法显示在屏幕上,而是借助于Viewgroup和View,这两个才是Android平台上最基本的两个用户界面表达单元。 2.android.v

1158

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

ScrollView嵌套ListView,.measure(0,0);空指针NullException

欢迎使用Markdown编辑器写博客本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客 导入导出Markdown文件 丰富的快捷键 快捷键 加粗 Ctrl + B 斜体 Ctrl + I 引用 Ctrl

cjj838559431的专栏 428

react native : measure 获取view 宽高位置/坐标

import React, {Component} from 'react'; import { Text, TouchableOpacity, UIManager, findNodeHandle, View, } from 'react-native'; export default class TextMeasure extends Component { UNSAFE_componentWillMount() { let that = t.

火星男孩的分享空间 3542

Android 获取layout宽高之前调用View.measure(0,0)的原因

private ConstraintLayout constraintLayout; constraintLayout=findViewById(R.id.screen_test); constraintLayout.measure(0,0); Log.i(TAG,"onCreate:"+constraintLayout.getMeasuredHeight()+","+constraintLay...

yh18668197127的博客 1345

measure(0, 0) 如何动态获得view的大小

延引如下资料 :   将view.onmeasure(0,0)设置为0的时候表示,此时不需要考虑父控件的布局问题,直接使用getMeasuredWidth和getMeasuredHeight获取此view的自身的实际大小,可以看下面的例子:这个是在网上引用的一段代码 1 2 3 4 5 6 7 8 9 10

当富网络 2144

关于View的知识

1.view的getWidth和getmeasureWidth的区别 这2个方法都是简单的赋值操作,具体的行为发生在onmeasure和layout里。 在onmeasure里,调用了setMeasureDimension,里面的getDefaultSize的方法,根据MeasureSpec返回相应的数值。 在setMeasureDimension里,根据getDefaultSize里...

weixin_43104619的博客 381

Android View绘制:measure,layout和draw

Android的View显示在界面上需要三步:测量,安放和绘制。

Summer舒的博客 2550

动态获取View的高度

设置动态复View的高度宽度有以下两制种方法: 1. getHeight() 方法这个方法必须要在View调用了onLayout方法后才能获得,为了监听onLayout方法,可以获得ViewTree观察者上的监听器来实现,具体代码为: ViewTreeObserver viewTreeObserver = bottomMenu.getViewTreeObserver(); viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver...

Jason_996的博客 378

Android 4.3 measure()空指针

这几天碰到一个bug,在调用onMeasure()时,发生空指针异常,导致app崩溃。  View listItem = adapter.getView(i, null, listView);  listItem.measure(0,0); 代码用在listView自动充满的代码中 经过定位后发现只有在4.3版本才会出现。 纠结了不少时间,经过查询资料与排查,发现了解决方法,特分享出

dxw002003的专栏 959

measure(widthMeasureSpec,heightMeasureSpec);

我们知道获取宽高一般写法是: 1 view.measure(0, 0); 2 view.getMeasuredHeight(); 拿宽高前什么时候可以直接用measure(0, 0);而什么时候不

qq_22808479的博客 692

View 的绘制 & 事件分发

View 的绘制 & 事件分发

简单记录 660
上一篇: Java 容器源码分析之 Deque 与 ArrayDeque
下一篇: Java 代码中看到数字中间带下划线的,如 1000_000 这种形式的数字的理解
MrCoderr
博客等级 码龄12年 39粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值