Android View的 getHeight 和 getMeasuredHeight 的区别

前言

先简单复习一下Android View 的 绘制顺序:

1、onMeasure(测量),先根据构造器传进来的LayoutParams(布局参数),测量view宽高。

2、onLayout(布局),再根据测量出来的宽高参数,进行布局

3、onDraw(绘制),最后绘制出View。

ps:案例中用到了dataBinding

1、使用LayoutParams改变View高度

效果:getHeight 和 getMeasuredHeight 的值是一样的,没有区别;

getWidth 和 getMeasuredWidth 也是同理。

        bind.btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) bind.textBox.getLayoutParams();             params.height += 10;bind.textBox.setLayoutParams(params);Log.d("TAG", "更新后 getHeight:" + bind.textBox.getHeight() + " --- getMeasuredHeight:" + bind.textBox.getMeasuredHeight());}});

2、使用layout改变View高度

效果:getHeight 的值在变化,而 getMeasuredHeight 的值没有变化,还是初始值。

getWidth 和 getMeasuredWidth 也是同理。

	bind.btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {bind.textBox.layout(bind.textBox.getLeft(),bind.textBox.getTop(),bind.textBox.getRight(),bind.textBox.getBottom() + 10);Log.d("TAG","更新后 getHeight:" + bind.textBox.getHeight() + " --- getMeasuredHeight:" + bind.textBox.getMeasuredHeight());}});

3、区别

通过以上方式可以看出,使用layout可以改变View 宽或高 度,但并不会更新View原始测量值,即使使用requestLayout()也不行。

源码:因为它是final类型,不可重写。

4、两种获取宽高值的应用场景

1、View布局完成(就是View执行完onLayout),使用 getWidth / getHeight,这是View源码。

    /*** Return the width of your view.** @return The width of your view, in pixels.*/@ViewDebug.ExportedProperty(category = "layout")public final int getWidth() {return mRight - mLeft;}/*** Return the height of your view.** @return The height of your view, in pixels.*/@ViewDebug.ExportedProperty(category = "layout")public final int getHeight() {return mBottom - mTop;}/*** Right position of this view relative to its parent.** @return The right edge of this view, in pixels.*/@ViewDebug.CapturedViewPropertypublic final int getRight() {return mRight;}/*** Left position of this view relative to its parent.** @return The left edge of this view, in pixels.*/@ViewDebug.CapturedViewPropertypublic final int getLeft() {return mLeft;}/*** Bottom position of this view relative to its parent.** @return The bottom of this view, in pixels.*/@ViewDebug.CapturedViewPropertypublic final int getBottom() {return mBottom;}/*** Top position of this view relative to its parent.** @return The top of this view, in pixels.*/@ViewDebug.CapturedViewPropertypublic final int getTop() {return mTop;}

1.1、自定义View 运行结果

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);Log.d("TAG", "onMeasure --- getLeft:" + getLeft()); // 0Log.d("TAG", "onMeasure --- getTop:" + getTop()); // 0Log.d("TAG", "onMeasure --- getRight:" + getRight()); // 0Log.d("TAG", "onMeasure --- getBottom:" + getBottom()); // 0Log.d("TAG", "onMeasure --- getWidth:" + getWidth()); // 0Log.d("TAG", "onMeasure --- getHeight:" + getHeight()); // 0}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);Log.d("TAG", "onMeasure --- getLeft:" + getLeft()); // 503Log.d("TAG", "onMeasure --- getTop:" + getTop()); // 871Log.d("TAG", "onMeasure --- getRight:" + getRight()); // 577Log.d("TAG", "onMeasure --- getBottom:" + getBottom()); // 923Log.d("TAG", "onMeasure --- getWidth:" + getWidth()); // 74    = 577 - 503Log.d("TAG", "onMeasure --- getHeight:" + getHeight()); // 52  = 923 - 871}

2、反之View没有布局完,使用 getMeasuredWidth / getMeasuredHeight,比如在onCreate中使用可以获取 宽高值,如果在此 使用 getWidth / getHeight 返回会是0,因为此时还没有布局完成。

注意:布局未完成前使用 getMeasuredWidth / getMeasuredHeight,要先主动通知系统测量,才会有值,如果布局已经完成,那就直接用,不需要这一步;

通知系统测量方法:measure(0,0),直接都写0就好,系统会返回正确的值。

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);bind = AppActivityMainBinding.bind(getLayoutInflater().inflate(R.layout.app_activity_main, null));setContentView(bind.getRoot());// 主动通知系统去测量bind.textBox的高度// 注意:在onCreate中,此时的布局还未完成,只有执行了这句代码,bind.textBox.getMeasuredHeight() 才会有值bind.textBox.measure(0,0);bind.showHeight.setText("getHeight:" + bind.textBox.getHeight() + " --- getMeasuredHeight:" + bind.textBox.getMeasuredHeight());    }

5、使用layout改变View宽高,会引发的问题

前言提到,onLayout(布局)是根据测量出来的宽高参数,进行布局的,虽然在视觉上改变了宽高,但测量的宽高值还是原始值,没有改变;

而在Android布局体系中,父View负责刷新、布局显示子View,当子View需要刷新时,则是通知父View来完成,就是循环遍历调用子View的 measure / layout / draw 方法。

由此得出,当布局中某个子View布局发生改变,这个父View就开始循环遍历调用子View的layout,通过布尔值changed判断当前子View是否需要重新布局,changed为true表示当前View的大小或位置改变了 。

这时就会发现 之前通过layout改变宽高的View,会被还原因为onLayout(布局)是根据测量出来的宽高参数,进行布局的,重要的话说三遍。

案例:

我新加了一个TextView,将值显示在屏幕上。

        <TextViewandroid:id="@+id/show_height"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

View没有发生改变?不,它改变了,但给TextView赋值后,TextView的宽高发生改变,通知父View刷新,父View开始循环遍历子View的layout方法,导致 通过layout改变宽高的View,又根据 原始测量值,重新布局还原了,由于执行的太快,所以视觉上看不到View这个过程。

日志:

20:29:39.933  D  MTextView --- onLayout --- bottom:1127 --- changed:true
20:29:39.935  D  更新TextView,触发MTextView的 onLayout方法
20:29:39.973  D  MTextView --- onLayout --- bottom:1117 --- changed:true

6、案例文件

MTextView.java

public class MTextView extends androidx.appcompat.widget.AppCompatTextView {public MTextView(@NonNull Context context) {super(context);}public MTextView(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int heightPxValue = MeasureSpec.getSize(heightMeasureSpec);Log.d("TAG", "MTextView --- onMeasure --- heightPxValue:" + heightPxValue);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);Log.d("TAG", "MTextView --- onLayout --- bottom:" + bottom + " --- changed:" + changed);}

app_activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"tools:context=".ui.activity.AppMainActivity"><TextViewandroid:id="@+id/show_height"android:layout_width="wrap_content"android:layout_height="wrap_content"/><Buttonandroid:id="@+id/btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="update"android:textAllCaps="false" /><com.example.xxx.ui.view.MTextViewandroid:id="@+id/text_box"style="@style/Font_303133_15_bold"android:layout_width="200dp"android:layout_height="100dp"android:background="@color/color_66000000"android:gravity="center"android:text="hello world" /></LinearLayout></layout>

AppMainActivity.java

public class AppMainActivity extends AppCompatActivity {private AppActivityMainBinding bind;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);bind = AppActivityMainBinding.bind(getLayoutInflater().inflate(R.layout.app_activity_main, null));setContentView(bind.getRoot());// bind.btn.setOnClickListener(new View.OnClickListener() {//    @Override//    public void onClick(View v) {//         LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) bind.textBox.getLayoutParams();             //         params.height += 10;//         bind.textBox.setLayoutParams(params);//         Log.d("TAG", "更新后 getHeight:" + bind.textBox.getHeight() + " --- getMeasuredHeight:" + bind.textBox.getMeasuredHeight());//    }// });// bind.btn.setOnClickListener(new View.OnClickListener() {//    @Override//    public void onClick(View v) {//        bind.textBox.layout(//                bind.textBox.getLeft(),//                bind.textBox.getTop(),//                bind.textBox.getRight(),//                bind.textBox.getBottom() + 10//        );//        Log.d("TAG","更新后 getHeight:" + bind.textBox.getHeight() + " --- getMeasuredHeight:" + bind.textBox.getMeasuredHeight());//    }// });bind.btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {bind.textBox.layout(bind.textBox.getLeft(),bind.textBox.getTop(),bind.textBox.getRight(),bind.textBox.getBottom() + 10);bind.showHeight.setText("getHeight:" + bind.textBox.getHeight() + " --- getMeasuredHeight:" + bind.textBox.getMeasuredHeight());Log.d("TAG","更新TextView,触发MTextView的 onLayout方法");}});}}

总结

在View没有布局完成前,想要获取 宽高,使用 getMeasuredWidth / getMeasuredHeight,记得先通知系统测量;

反之只要显示在屏幕上,getWidth / getHeight 就能拿到值,还是时时数据。

补充一下,如果在xml中给View设置了visibility="gone"注意是xml,getWidth / getHeight 也拿不到值,如果是 visibility="invisible",不受影响。

再如果 在xml中给View设置了visibility="gone",在代码中设置成setVisibility(View.VISIBLE)第一次拿不到值,因为还没有layout完成,之后就可以拿到了,后面再给它设置成setVisibility(View.GONE),也不会受影响,因为已经布局过了。代码在这,我都试过了,核心就是看View有没有onLayout完成。

Activity

    @Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);Log.d("TAG", "getHeight:" + bind.btn.getHeight()); // 0new Handler().postDelayed(new Runnable() {@Overridepublic void run() {Log.d("TAG", "getHeight:" + bind.btn.getHeight()); // 0bind.btn.setVisibility(View.VISIBLE); // 设置显示Log.d("TAG", "getHeight:" + bind.btn.getHeight()); // 0}}, 2000);new Handler().postDelayed(new Runnable() {@Overridepublic void run() {Log.d("TAG", "getHeight:" + bind.btn.getHeight()); // 126bind.btn.setVisibility(View.GONE); // 设置消失Log.d("TAG", "getHeight:" + bind.btn.getHeight()); // 126}}, 5000);new Handler().postDelayed(new Runnable() {@Overridepublic void run() {Log.d("TAG", "getHeight:" + bind.btn.getHeight()); // 126}}, 8000);}

Xml

        <Buttonandroid:id="@+id/btn"android:visibility="gone"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="update"android:textAllCaps="false" />

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/213916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL进阶 | 自连接

概述 SQL的自连接是指在一个SQL表中&#xff0c;使用自身表格中的实例进行联接并查询的操作。自连接通常使用别名来标识一个表格&#xff0c;在自连接中&#xff0c;表格被视为两个不同的表格&#xff0c;并分别用不同的别名来标识。然后&#xff0c;在WHERE子句中使用这些别名…

oracle异常:ORA-03297:文件包含在请求的 RESIZE 值以外使用的数据

出现这个问题&#xff0c;主要是在对表空间扩容的时候&#xff0c;扩容的大小<实际数据文件大小 1、扩容的语句 alter database datafile D:\APP\ADMINISTRATOR\ORADATA\ORCL\USER.DBF resize 2G; 2、若何确定扩容大小是否比实际文件大 根据路径找到文件&#xff0c;查看…

二十、FreeRTOS之Tickless低功耗模式

本节需要掌握以下内容&#xff1a; 1&#xff0c;低功耗模式简介&#xff08;了解&#xff09; 2&#xff0c; Tickless模式详解&#xff08;熟悉&#xff09; 3&#xff0c; Tickless模式相关配置项&#xff08;掌握&#xff09; 4&#xff0c;Tickless低功耗模式实验&…

自定义异步任务管理器和线程

import com.lancoo.common.utils.Threads; import com.lancoo.common.utils.spring.SpringUtils;import java.util.TimerTask; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit;/*** 异步任务管理器* * author lancoo*/ public c…

操作系统大会 openEuler Summit 2023即将召开,亮点不容错过

【12月11日&#xff0c;北京】数字化、智能化浪潮正奔涌而来。操作系统作为数字基础设施的底座&#xff0c;已经成为推动产业数字化、智能化发展的核心力量&#xff0c;为数智未来提供无限可能。12月15-16日&#xff0c;以“崛起数字时代 引领数智未来”为主题的操作系统大会 &…

〖Python网络爬虫实战㊷〗- 极验滑块介绍(四)

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;订阅本专栏前必读关于专栏〖Python网络爬虫实战〗转为付费专栏的订阅说明作者&#xff1…

【ArcGIS Pro微课1000例】0049:根据坐标快速定位(创建点位)的常见方法

文章目录 一、转到XY1. 闪烁位置2. 平移3. 标记位置二、定位1. 坐标定位2. 添加到图形3. 添加至要素类三、添加XY坐标四、创建点要素一、转到XY 举例:经纬度坐标:113.2583286东, 23.1492340北 。 1. 闪烁位置 输入坐标,点击闪烁位置工具,即可在对应的位置出现一个绿色闪烁…

SQL注入漏洞利用

预计更新SQL注入概述 1.1 SQL注入攻击概述 1.2 SQL注入漏洞分类 1.3 SQL注入攻击的危害 SQLMap介绍 2.1 SQLMap简介 2.2 SQLMap安装与配置 2.3 SQLMap基本用法 SQLMap进阶使用 3.1 SQLMap高级用法 3.2 SQLMap配置文件详解 3.3 SQLMap插件的使用 SQL注入漏洞检测 4.1 SQL注入…

shiro入门demo

搭建springboot项目&#xff0c;引入以下依赖&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--单元测试--><depe…

集的增删操作

集是可以修改的&#xff0c;增加元素可以用add和update函数。删除可以用pop、discard、remove等函数。 1 增加集里的元素 add函数的参数视为一个整体插入到集里&#xff0c;而update函数传入的参数是把要传入的元素拆分&#xff0c;做为个体传入到集合中。 s set("hell…

.9.png的创建

1、创建.9.png 选中图片&#xff0c;右击&#xff0c;选择Create 9-Patch file&#xff0c;点击确定会生成一个xxx.9.png的图片 2、绘制拉伸区域 在图片的最外边界绘制拉伸区域&#xff0c;按住鼠标左键不放&#xff0c;绘制完成后保存就可以使用了。绘制结果示意如下&…

phpstudy小皮(PHP集成环境)下载及使用

下载 https://www.xp.cn/download.html直接官网下载即可&#xff0c;下载完解压是个.exe程序&#xff0c;直接点击安装就可以&#xff0c;它会自动在D盘目录为D:\phpstudy_pro 使用 phpMyAdmin是集成的数据库可视化&#xff0c;这里需要下载一下&#xff0c;在软件管理-》网站程…

OPPO怎么录屏?教程来了,让你成为录屏达人

“有人知道OPPO怎么录屏吗&#xff0c;前阵子刚买的OPPO手机&#xff0c;用起来感觉挺流畅的&#xff0c;功能也很齐全&#xff0c;最近因为工作原因&#xff0c;需要用到录屏功能&#xff0c;但是我不知道怎么打开&#xff0c;就想问问大伙&#xff0c;OPPO怎么录屏呀。” 在…

Redis分片集群一步一步全过程搭建

文章目录 Redis搭建分片集群1. 搭建的分片集群结构2.准备实例和配置&#xff08;1&#xff09;创建目录&#xff08;2&#xff09;创建配置文件&#xff08;3&#xff09;将这个文件拷贝到每个目录下&#xff08;4&#xff09;修改每个目录下的redis.conf&#xff0c;将其中的6…

Yocto 还是 Buildroot,构建自定义嵌入式系统时,您会选择哪一种?

假设您正在采用集成平板开发新一代大型智能微波炉。这个创意不错吧&#xff01;现在&#xff0c;您需要构建自定义操作系统&#xff0c;在保证不会烧焦食物&#xff08;更不要烧毁房屋哦&#xff09;的前提下&#xff0c;辅助管理各项事务。除此之外&#xff0c;您还需要创建一…

px? pt? dp? em?rem?vw?vh?ch?ex?这些单位你了解吗?

目录 前言 一、常见单位 1、px单位 2、dp单位 3、pt单位 4、百分比% 5、em单位 6、rem单位 7、vw和vh单位 8、ch、ex单位 二、如何换算 1、 pt和px换算 2、px和dp换算 3、em和px换算 4、rem和px换算 三、总结 前言 前端开发在日常设计中除了最常用的 px 以外&…

第二十八章 控制到 XML 模式的映射 - 流类到 XML 类型的映射

文章目录 第二十八章 控制到 XML 模式的映射 - 流类到 XML 类型的映射将集合属性映射到 XML 模式 第二十八章 控制到 XML 模式的映射 - 流类到 XML 类型的映射 如果类或属性基于流&#xff0c;则它将投影为 XML 类型&#xff0c;如下表所示&#xff1a; IRIS 流的 XML 类型 …

使用BeautifulSoup 4和Pillow合并网页图片到一个PDF:一种高效的方式来处理网页图像

背景 ​ 网页上的培训材料&#xff0c;内容全是PPT页面图片。直接通过浏览器打印&#xff0c;会存在只打印第一页&#xff0c;并且把浏览器上无效信息也打印出来情况。但目标是希望将页面图片全部打印为pdf形式。 实现方案 利用网页“另存为”&#xff0c;将页面内所有图片资…

官宣!「湾区之光群星演唱会」拉开2024新年音乐华丽序幕!

万众期待&#xff0c;群星荟萃&#xff01;青春宝安时尚湾区——湾区之光群星演唱会即将在2024年1月5日闪耀亮相深圳宝安。 华语歌坛巨星天后齐聚一堂&#xff0c;携手多位实力唱将&#xff0c;共同呈现一场无与伦比的演唱会盛宴&#xff01;在深情而又充满力量的歌声之中&…

Linux修复磁盘坏道,重新挂载硬盘

修复磁盘 挂载报错&#xff1a; [rootlocalhost ~]$ mount /dev/sdb /mnt/mydevmount: /dev/sdb is write-protected, mounting read-only mount: wrong fs type, bad option, bad superblock on /dev/sdb,missing codepage or helper program, or other errorIn some cases …