视图的getWidth()和getHeight()返回0
我正在动态创建我的android项目中的所有元素。 我正在尝试获取按钮的宽度和高度,以便可以旋转该按钮。 我只是想学习如何使用android语言。 但是,它返回0。
我做了一些研究,发现需要在onCreate()
方法之外的地方进行。 如果有人可以给我一个例子,那就太好了。
这是我当前的代码:
package com.animation;import android.app.Activity;
import android.os.Bundle;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.LinearLayout;public class AnimateScreen extends Activity {//Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);LinearLayout ll = new LinearLayout(this);LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);layoutParams.setMargins(30, 20, 30, 0);Button bt = new Button(this);bt.setText(String.valueOf(bt.getWidth()));RotateAnimation ra = new RotateAnimation(0,360,bt.getWidth() / 2,bt.getHeight() / 2);ra.setDuration(3000L);ra.setRepeatMode(Animation.RESTART);ra.setRepeatCount(Animation.INFINITE);ra.setInterpolator(new LinearInterpolator());bt.startAnimation(ra);ll.addView(bt,layoutParams);setContentView(ll);
}
任何帮助表示赞赏。
#1楼
我们可以用
@Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);//Here you can get the size!}
#2楼
我使用了这种解决方案,我认为它比onWindowFocusChanged()更好。 如果打开DialogFragment,然后旋转电话,则仅当用户关闭对话框时才会调用onWindowFocusChanged):
yourView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {// Ensure you call it only once :yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);// Here you can get the size :)}});
编辑:不推荐使用removeGlobalOnLayoutListener,现在您应该这样做:
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {// Ensure you call it only once :if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {yourView.getViewTreeObserver().removeOnGlobalLayoutListener(this);}else {yourView.getViewTreeObserver().removeGlobalOnLayoutListener(this);}// Here you can get the size :)
}
#3楼
如果需要在窗口小部件显示之前获取其宽度,可以使用getMeasuredWidth()或getMeasuredHeight()。
myImage.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int width = myImage.getMeasuredWidth();
int height = myImage.getMeasuredHeight();
#4楼
基本问题是,您必须等待绘图阶段进行实际测量(尤其是使用诸如wrap_content
或match_parent
类的动态值),但是通常直到onResume()
为止,这个阶段还没有完成。 因此,您需要一种解决方案来等待此阶段。 有一个不同的可能的解决方案:
1.收听绘图/布局事件:ViewTreeObserver
一个ViewTreeObserver被激发用于不同的绘图事件。 通常, OnGlobalLayoutListener
是获取度量所需的,因此在布局阶段之后将调用侦听器中的代码,因此度量已准备就绪:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {view.getViewTreeObserver().removeOnGlobalLayoutListener(this);view.getHeight(); //height is ready}});
注意:监听器将被立即删除,因为否则它将在每个布局事件上触发。 如果您必须支持SDK Lvl <16的应用程序,请使用此命令注销监听器:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2.将可运行对象添加到布局队列:View.post()
不是很出名,也是我最喜欢的解决方案。 基本上,只需将View的post方法与您自己的runnable一起使用即可。 如Romain Guy所述,这基本上是在视图的尺寸,布局等之后将您的代码排队:
UI事件队列将按顺序处理事件。 调用setContentView()后,事件队列将包含一条消息,要求进行重新布局,因此您发布到队列中的所有内容都会在布局通过后发生
例:
final View view=//smth;
...
view.post(new Runnable() {@Overridepublic void run() {view.getHeight(); //height is ready}});
相对于ViewTreeObserver
的优势:
- 您的代码仅执行一次,而不必在执行后禁用观察器,这可能会很麻烦
- 不太冗长的语法
参考文献:
- https://stackoverflow.com/a/3602144/774398
- https://stackoverflow.com/a/3948036/774398
3.覆盖Views的onLayout方法
仅在逻辑可以封装在视图本身中的情况下,这才是切实可行的,否则,这是一种非常冗长且繁琐的语法。
view = new View(this) {@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);view.getHeight(); //height is ready}
};
还请记住,onLayout将被调用多次,因此请考虑在方法中执行的操作,或者在第一次后禁用代码
4.检查是否已经过布局阶段
如果您在创建ui时执行了多次代码,则可以使用以下支持v4 lib方法:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {viewYouNeedHeightFrom.getHeight();
}
如果视图自从上次附着到窗口或从窗口分离以来已经经过至少一种布局,则返回true。
附加:获取静态定义的测量
如果只需要获取静态定义的高度/宽度,则可以使用以下方法执行此操作:
View.getMeasuredWidth()
View.getMeasuredHeigth()
但是请注意,这可能与绘制后的实际宽度/高度不同。 Javadoc完美地描述了差异:
视图的大小用宽度和高度表示。 一个视图实际上具有两对宽度和高度值。
第一对称为测量宽度和测量高度。 这些尺寸定义视图在其父级中的大小(有关更多详细信息,请参见布局。)可以通过调用getMeasuredWidth()和getMeasuredHeight()获得测量尺寸。
第二对简称为宽度和高度,有时也称为图纸宽度和图纸高度。 这些尺寸定义了屏幕上,绘制时和布局后视图的实际尺寸。 这些值可以但不必与测量的宽度和高度不同。 宽度和高度可以通过调用getWidth()和getHeight()获得。
#5楼
您太早调用getWidth()
了。 UI尚未调整大小并在屏幕上布置。
无论如何,我怀疑您是否想做自己正在做的事情—动画化的小部件不会更改其可点击区域,因此无论按钮如何旋转,按钮仍将响应原始方向的单击。
话虽如此,您可以使用维度资源来定义按钮的大小,然后从布局文件和源代码中引用该维度资源,以避免出现此问题。
#6楼
我宁愿使用OnPreDrawListener()
而不是addOnGlobalLayoutListener()
,因为它被更早地调用了。
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){@Overridepublic boolean onPreDraw(){if (view.getViewTreeObserver().isAlive())view.getViewTreeObserver().removeOnPreDrawListener(this);// put your code herereturn true;}});
#7楼
正如Ian在此Android Developers线程中指出的那样:
无论如何,关键是要在构造所有元素并将其添加到其父视图之后 ,对窗口内容进行布局。 它必须是这种方式,因为在您知道View包含哪些组件以及它们包含什么等等之前,没有明智的方法可以对其进行布局。
底线是,如果在构造函数中调用getWidth()等,它将返回零。 该过程是在构造函数中创建所有视图元素,然后等待调用View的onSizeChanged()方法-那是您首次确定实际大小时,因此才是设置GUI元素的大小。
还要注意,有时会使用零参数调用onSizeChanged()-检查这种情况,然后立即返回(因此在计算布局等时不会除以零)。 一段时间后,它将使用实际值进行调用。
#8楼
如果您使用的是RxJava和RxBindings,则使用一根 衬板 。 没有样板的类似方法。 如蒂姆·奥丁 ( Tim Autin)的回答一样,这也解决了黑客抑制警告的问题。
RxView.layoutChanges(yourView).take(1).subscribe(aVoid -> {// width and height have been calculated here});
就是这个。 即使从未调用,也无需取消订阅。
#9楼
Kotlin扩展程序,用于观察全局布局,并在动态准备好高度时执行给定的任务。
用法:
view.height { Log.i("Info", "Here is your height:" + it) }
实现方式:
fun <T : View> T.height(function: (Int) -> Unit) {if (height == 0)viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {override fun onGlobalLayout() {viewTreeObserver.removeOnGlobalLayoutListener(this)function(height)}})else function(height)
}
#10楼
如果应用程序在后台运行,则视图消失将返回0作为高度。 这是我的代码(1oo%有效)
fun View.postWithTreeObserver(postJob: (View, Int, Int) -> Unit) {viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {override fun onGlobalLayout() {val widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)val heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)measure(widthSpec, heightSpec)postJob(this@postWithTreeObserver, measuredWidth, measuredHeight)if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {@Suppress("DEPRECATION")viewTreeObserver.removeGlobalOnLayoutListener(this)} else {viewTreeObserver.removeOnGlobalLayoutListener(this)}}})
}
#11楼
如果您使用的是Kotlin
leftPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {override fun onGlobalLayout() {if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {leftPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)}else {leftPanel.viewTreeObserver.removeGlobalOnLayoutListener(this)}// Here you can get the size :)leftThreshold = leftPanel.width}})
#12楼
高度和宽度为零,因为在您请求视图的高度和宽度时尚未创建视图。 一种最简单的解决方案是
view.post(new Runnable() {@Overridepublic void run() {view.getHeight(); //height is readyview.getWidth(); //width is ready}});
与其他方法相比,该方法短而明快,因此非常好。
#13楼
我们需要等待视图将被绘制。 为此,请使用OnPreDrawListener。 Kotlin示例:
val preDrawListener = object : ViewTreeObserver.OnPreDrawListener {override fun onPreDraw(): Boolean {view.viewTreeObserver.removeOnPreDrawListener(this)// code which requires view size parametersreturn true}}view.viewTreeObserver.addOnPreDrawListener(preDrawListener)
#14楼
也许这可以帮助某人:
为View类创建扩展功能
文件名:ViewExt.kt
fun View.afterLayout(what: () -> Unit) {if(isLaidOut) {what.invoke()} else {viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {override fun onGlobalLayout() {viewTreeObserver.removeOnGlobalLayoutListener(this)what.invoke()}})}
}
然后可以将其用于以下任何视图:
view.afterLayout {do something with view.height
}
#15楼
AndroidX有多个扩展功能,可以帮助您有这方面的工作,里面androidx.core.view
您需要为此使用Kotlin。
最适合这里的是doOnLayout
:
布置此视图时执行给定的操作。 如果视图已被布局并且尚未请求布局,则将立即执行该动作,否则,将在下一个视图被布局后执行该动作。
该动作仅在下一个布局上被调用一次,然后被删除。
在您的示例中:
bt.doOnLayout {val ra = RotateAnimation(0,360,it.width / 2,it.height / 2)... more code
}
依赖关系: androidx.core:core-ktx:1.0.0
#16楼
发生这种情况是因为视图需要更多的时间来膨胀。 因此,应在主线程上调用view.post { ... }
以确保您的view
已被view.height
,而不是在主线程上调用view.width
和view.height
。 在科特林:
view.post{width}
view.post{height}
在Java中,你也可以调用getWidth()
和getHeight()
的方法Runnable
并通过Runnable
来view.post()
方法。
view.post(new Runnable() {@Overridepublic void run() {view.getWidth(); view.getHeight();}});
视图的getWidth()和getHeight()返回0相关推荐
- 关于Access数据库执行Update语句后,不报错,但影响行数总是返回0的问题
最近碰到一个奇怪的问题,使用Access数据库执行Update语句后,不报错,但影响行数总是返回0. 因为是第一次碰到这个问题,纠结了半天.后来在网上搜索得到解决方案: SQL语句传参数的顺序和语句中 ...
- mysql count 返回0_如何在MySQL中使用COUNT時返回0而不是null
我正在使用此查詢返回存儲在$ sTable中的歌曲列表以及存儲在$ sTable2中的總項目的COUNT.如何在MySQL中使用COUNT時返回0而不是null /* * SQL queries * ...
- vim支持python/dyn,但has返回0
echo has("python") echo has("python3") 等等均返回0 其实本质是会去寻找 python27.dll python39.dl ...
- android wifimanager权限,Android 6.0.1 - 权限问题= wifiManager.getScanResults()返回0
permissionsList.add()不起作用,但MainActivity.this.requestPermissions()正常工作.问题是它带来一个对话框询问用户是否允许位置权限.Androi ...
- 踩坑记录:请求接口status返回0
欢迎关注博主博客: https://lvsige.top/ 现象: H5请求openapi接口,ios可以正常请求,返回200. 但是安卓请求接口返回0 用户通过"领取链接"扫码进 ...
- C语言试题三十一之判断字符串是否为回文?若是则函数返回1,主函数中输出yes,否则返回0,主函数中输出no。回文是指顺读和倒读都是一样的字符串。
1. 题目 请编写函数function,该函数的功能是:判断字符串是否为回文?若是则函数返回1,主函数中输出yes,否则返回0,主函数中输出no.回文是指顺读和倒读都是一样的字符串. 2 .温馨提示 ...
- javascript---parseInt(08)或parseInt(09)转换返回0的解决办法
javascript parseInt函数使用率非常高,主要功能是将一个string转换为integer.有两个重载: parseInt(s); parseInt(s,radix) 第一个方式不再多说 ...
- mysql受影响的行 0_为什么更新/删除成功时受影响的行返回0?
我有声明: INSERT INTO infotbl(name, phone) VALUES('Alex', '9999999'); 并更新它: UPDATE infotbl SET name = 'A ...
- JavaScript中的ParseInt(08)和“09”返回0的原因分析及解决办法
今天在程序中出现一个bugger ,调试了好久,最后才发现,原来是这个问题. 做了一个实验: alert(parseInt("01")),当这个里面的值为01====>07时 ...
最新文章
- 为什么傅里叶变换可以代替自注意力机制
- python好学实用吗-都说python很简单 真的很好学么?
- 2018阿里云云数据库RDS核心能力演进
- Windows蓝屏(Beginning Dump of Physical Memory)
- 微信红包封面小程序源码-后台独立版-带测评积分功能源码
- 没有匹配的验证协议_ORA-28040:没有匹配的验证协议
- 怎样让公式编号不从1开始
- 定义在计算机中怎么翻译,Profile在计算机中翻译成什么
- Scientific Linux 6.4安装详程
- 2. 虚拟机常用操作
- 不意外:Facebook上市遭遇滑铁卢
- 可长时间佩戴的耳机真的存在吗?骨传导耳机是否对耳朵伤害更小?
- 大数据(一)数据采集 3
- 媒体格式有几种,媒体格式的异同
- 红帽Redhat—Linux软件管理
- Word功能-“多级列表”-用法笔记
- 20190411(已解决)对分页预览的认识_yingruiyuelin_新浪博客
- BTC菠萝B1 超高性价比 阿瓦隆1246现货 现货秒发
- 060201面积-定积分在几何学上的应用-定积分的应用
- 电影分级USA、HK
热门文章
- malloc calloc realloc的对比
- python装饰器由浅入深_由浅入深,走进Python装饰器-----第五篇:进阶--类装饰类
- PHP学习笔记-GD库与Jpgraph的使用
- synchronized同时对原子性、可见性、有序性的保证
- Broadcast应用场景分析
- (0098)iOS开发之应用间的分享系列(3)
- java线程callback,Java线程之异步回调(Callback)
- ThinkPHP5 清除runtime缓存文件
- jquery and jquery validation 常见问题解决
- C++设计模式 之 “组件协作”模式:Template Method、Strategy、Observer