android如何获取view在布局中的高度与宽度详解
作者:专注移动开发技术 发布时间:2023-08-14 17:17:51
前言
可能很多情况下,我们都会有在activity中获取view 的尺寸大小(宽度和高度)的需求。面对这种情况,很多同学立马反应:这么简单的问题,还用你说?你是不是傻。。然后立马写下getWidth()、getHeight()等方法,洋洋得意的就走了。然而事实就是这样的吗?实践证明,我们这样是获取不到View的宽度和高度大小的。
当我们在 onCreate() 方法中获取某个 View 组件的宽度和高度,直接调用 getWidth()、getHeight()、getMeasuredWidth()、getMeasuredHeight() 方法只会得到 0。这是什么原因呢?下面来一起看看吧
实现方法
一、使用 View.measure 测量 View
该方法测量的宽度和高度可能与视图绘制完成后的真实的宽度和高度不一致。
int width = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
int height = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
view.measure(width, height);
view.getMeasuredWidth(); // 获取宽度
view.getMeasuredHeight(); // 获取高度
二、使用 ViewTreeObserver. OnPreDrawListener 监听事件
在视图将要绘制时调用该监听事件,会被调用多次,因此获取到视图的宽度和高度后要移除该监听事件。
view.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
view.getWidth(); // 获取宽度
view.getHeight(); // 获取高度
return true;
}
});
三、使用 ViewTreeObserver. OnGlobalLayoutListener 监听事件
在布局发生改变或者某个视图的可视状态发生改变时调用该事件,会被多次调用,因此需要在获取到视图的宽度和高度后执行 remove 方法移除该监听事件。
view.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
view.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
else {
view.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
view.getWidth(); // 获取宽度
view.getHeight(); // 获取高度
}
});
四、重写 View 的 onSizeChanged 方法
在视图的大小发生改变时调用该方法,会被多次调用,因此获取到宽度和高度后需要考虑禁用掉代码。
该实现方法需要继承 View,且多次被调用,不建议使用。
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
view.getWidth(); // 获取宽度
view.getHeight(); // 获取高度
}
五、重写 View 的 onLayout 方法
该方法会被多次调用,获取到宽度和高度后需要考虑禁用掉代码。
该实现方法需要继承 View,且多次被调用,不建议使用。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getWidth(); // 获取宽度
view.getHeight(); // 获取高度
}
六、使用 View.OnLayoutChangeListener 监听事件(API >= 11)
在视图的 layout 改变时调用该事件,会被多次调用,因此需要在获取到视图的宽度和高度后执行 remove 方法移除该监听事件。
view.addOnLayoutChangeListener(
new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int l, int t, int r, int b,
int oldL, int oldT, int oldR, int oldB) {
view.removeOnLayoutChangeListener(this);
view.getWidth(); // 获取宽度
view.getHeight(); // 获取高度
}
});
七、使用 View.post() 方法
Runnable 对象中的方法会在 View 的 measure、layout 等事件完成后触发。
UI 事件队列会按顺序处理事件,在 setContentView() 被调用后,事件队列中会包含一个要求重新 layout 的 message,所以任何 post 到队列中的 Runnable 对象都会在 Layout 发生变化后执行。
该方法只会执行一次,且逻辑简单,建议使用。
view.post(new Runnable() {
@Override
public void run() {
view.getWidth(); // 获取宽度
view.getHeight(); // 获取高度
}
});
以上为转载内容,个人学习收藏记录
下面是自己的学习记录。
首先第一个方法,以前用过,确实不准确,猜测是应该是因为参数没有用好,因为参数只使用UNSPECIFIED未指定的测量方式,一般像Wrap_Content,才是该测量方式。
这里贴一个比较好用的, AndroidUtilCode收藏的方法。
public static int[] measureView(final View view) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp == null) {
lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
}
int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
int lpHeight = lp.height;
int heightSpec;
if (lpHeight > 0) {
heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY);
} else {
heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
}
view.measure(widthSpec, heightSpec);
return new int[]{view.getMeasuredWidth(), view.getMeasuredHeight()};
}
然后是自己在做自定义view的时候,需要在一次add代码创建的view,使用上面的方法无法获得宽高,因为我使用的是ScrollView。像在自定义中,加载一次布局,应该选中最后一个post的方法最为使用。
另外还用的多的,应该是第三种方式,一般在外部使用,比如需要等待Recyclerview绘制完成后进行的操作。
来源:https://blog.csdn.net/qq_33275597/article/details/78668066


猜你喜欢
- 简介在Spring 5中,Spring MVC引入了webFlux的概念,webFlux的底层是基于reactor-netty来的,而rea
- 1. 异常处理概述空指针引用 NPE 是编程语言最常见的异常,数十年来无处不在的和程序打交道,在Java中,我们使用“防
- 本文是一个 Spring 扩展支持 SPEL 的简单模式,方便第三方通过 Spring 提供额外功能。简化版方式这种方式可以在任何能获取Ap
- 对象类型转换分为向上转型和向下转型(强制对象转型)。 向上转型是子对象向父对象转型的过程,例如猫类转换为动物类;向下转型是强制转型实现的,是
- 本文实例讲述了Android实现音量调节的方法。分享给大家供大家参考。具体如下:main.xml布局文件:<?xml version=
- 接口可以声明事件。 下面的示例演示如何在类中实现接口事件。 这些规则基本上都与实现任何接口方法或属性时的相同。在类中实现接口事件在类中声明事
- 在项目中经常会需要应用弹出一些自定义的窗口,这时候Android自带的系统Dialog就无法满足我们的需求了,为了满足项目需求,我们可以使用
- Android 仿微信的键盘切换(录音,表情,文字,其他),IM通讯,类似朋友圈只要涉及到文字等相关的app都会要涉及到键盘的处理,今天就给
- 一、新建项目我们这次直接从IEDA创建项目,具体配置如下,还是万年的Java8。二、docker-compose 配置mongoDBdock
- 关于Android开发可以使用的工具有eclipse和Android studio等,这两个工具都各有各的好处和不足。studio是谷歌推出
- 本文实例讲述了winform实现创建最前端窗体的方法。分享给大家供大家参考。具体实现方法如下:一、需求:1).需要这个窗体始终处于前端而且可
- 本文实例为大家分享了javaweb文件打包批量下载,供大家参考,具体内容如下// 批量下载未批改作业 @RequestMapping(val
- 本文实例为大家分享了android studio实现简单计算器的具体代码,供大家参考,具体内容如下布局:<?xml version=&
- 零、动态库 System.Math.dll引入动态库 using System.Math;Math 为通用数学函数、对数函数、三角函数等提供
- Jenkins 关闭和重启我们用jar -jar jenkins.war来启动jenkins服务器,那么我们如何关闭或者重启jenkins服
- 一、直接执行SQL查询:1、mappers文件节选<resultMap id="AcModelResultMap"
- maven报错:Failed to execute goal on project项目结构在hzz-entity项目上运行Maven ins
- 目录一、需求二、步骤三、结果一、需求把以下txt中含“baidu”字符串的链接输出到一个文件,否则输出到另外一个文件。二、步骤1.LogMa
- 需求: 给定一个URL地址, 例如: http://www.cncounter.com/tools/shorturl.php, 解析对应的I
- 文章描述这个程序也记不清是什么时候写的了,犹记得那时我还很年轻,偶然从网上看到了这样一个类似的标题(AI五子棋的实现),进去后看到那个是ja