Android: 在onCreate()中获得对象尺寸
onCreate() 中 View 尚未绘制完成
很多时候,我们需要在某个界面刚刚加载的时候,执行一些对 View 进行操作的代码,通常我们把这些代码放在 Activity 的 onCreate() 方法或 Fragment 的 onCreateView() 方法中。但因为在这些 Hook 方法被调用时,View 并没有绘制完成,很多操作不能生效。
比如,在 onCreate() 中调用某个按钮的 myButton.getHeight(),得到的结果永远是0。不想花时间慢慢看的同学,可以直接去看最后结论中的解决方案。
Button myButton = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
myButton = (Button) findViewById(R.id.button1);
// 尝试在 onCreate() 中获取控件尺寸
int h = myButton.getHeight();
Log.i(TAG, "onCreate(): Height=" + h); // 得到的结果是 Height=0
// ...
}
类似的情况还有很多,笔者之前自己写了一个下拉刷新的 ListView,希望在 Fragment 完成绘制后,立刻执行一次刷新,并将代码写在了 onCreateView() 中。结果是,列表确实进行了刷新操作,但是没有下拉刷新的动画。
更晚调用的生命周期函数
笔者开始以为,既然 onCreate() 中,控件尚未绘制完成,那么将代码写在更晚执行的一些生命周期函数中,问题是不是能得到解决呢?之后笔者分别在 Activity 中的一些常用的 Hook 函数中,尝试获取控件的尺寸,得到如下结果(按被执行的顺序排列):
onCreate(): Height=0
onStart(): Height=0
onPostCreate(): Height=0
onResume(): Height=0
onPostResume(): Height=0
onAttachedToWindow(): Height=0
onWindowsFocusChanged(): Height=1845
可以看到,直到 onWinodwsFocusChanged() 函数被调用,我们才能得到正确的控件尺寸。其他 Hook 函数,包括在官方文档中,描述为在 Activity 完全启动后才调用的 onPostCreate() 和 onPostResume() 函数,均不能得到正确的结果。
遗憾的是,虽然在 onWinodwsFocusChanged() 函数中,可以得到正确的控件尺寸。但这只在 Activity 中奏效,而在 Fragment 中,该方法并不能生效。
更多的解决方案
1. 使用 ViewTreeObserver 提供的 Hook 方法。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
myButton = (Button) findViewById(R.id.button1);
// 向 ViewTreeObserver 注册方法,以获取控件尺寸
ViewTreeObserver vto = myButton.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
int h = myButton.getHeight();
Log.i(TAG, "Height=" + h); // 得到正确结果
// 成功调用一次后,移除 Hook 方法,防止被反复调用
// removeGlobalOnLayoutListener() 方法在 API 16 后不再使用
// 使用新方法 removeOnGlobalLayoutListener() 代替
myButton.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
// ...
}
该方法在 onGlobalLayout() 方法将在控件完成绘制后调用,因而可以得到正确地结果。该方法在 Fragment 中,也可以使用。
2. 使用 View 的 post() 方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
myButton = (Button) findViewById(R.id.button1);
// 使用myButton 的 post() 方法
myButton.post(new Runnable() {
@Override
public void run() {
int h = myButton.getHeight();
Log.i(TAG, "Height=" + h); // 得到正确结果
}
});
// ...
}
该方法同样在 Fragment 中适用,是目前笔者发现的最佳解决方案。
注意:通过调用测量对象的 post() 方法注册的 Runnable 总在对象完全绘制后才调用,所以可以得到正确的结果。但直接在 onCreate() 中,使用 new Handler().post(mRunnable) 并不能得到正确的结果。
很多教程中,通过延迟一个毫秒数,即 new Handler().postDelayed(mRunnable, 500),来调用执行实际测量工作的 Runnable。这样虽然能得到正确的结果,但显然不是一个好的解决方案:太小的毫秒数不能保证控件完成绘制,太大的毫秒数,会严重破坏用户的操作体验。
结论
如果需要在某个 View 完成绘制后,立刻执行一段代码(如需要获取控件尺寸),最优雅的做法是:在 onCreate() 等生命周期函数中,调用该 View 的 post() 方法。
(参见上面的代码)
使用 ViewTreeObserver 注册 OnGlobalLayoutListener,或使用 Activity 的 onWinodwsFocusChanged() 方法,也可以达到相同目的。
Android: 在onCreate()中获得对象尺寸的更多相关文章
- Android在onCreate()中获得控件尺寸
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSt ...
- Android在OnCreate中获取控件的宽度和高度
在Android中,有时需要对控件进行测量,得到的控件宽度和高度可以用来做一些计算.在需要自适应屏幕的情况下,这种计算就显得特别重要.另一方便,由于需求的原因,希望一进入界面后,就能得到控件的宽度和高 ...
- Android 在OnCreate()中获取控件高度与宽度
试过在OnCreate()中获取控件高度与宽度的童鞋都知道,getWidth()与getHeight()方法返回是0,具体原因 看一下Activity的生命周期 就会明白. 上代码: 方法一: int ...
- Android在onCreate中获取控件的宽高
在某些需求下,我们需要在onCreate的时候就获取到控件的宽高,但是如果直接用view.getWidth()或view.getHeight()会得到0.这是因为在onCreate执行的时候,控件还没 ...
- 如何获取Android系统中申请对象的信息
最近一直在做有关内存方面的优化工作,在做优化的过程,除了关注内存的申请量以及GC的情况之外,我们经常需要想方法找出是那些对象占用了大量内存,以及他们是如何导致GC的,这意味着我们需要获取对象申请的信息 ...
- Android中Parcelabel对象的使用和理解
1. Parcelable接口 Interface for classes whose instances can be written to and restored from a Parcel. ...
- Android应用项目中BaseAdapter、SimpleAdapter和ArrayAdapter中的三种适配器
一.写在前面: 本次我们来讲解一下Android应用中三个适配器:BaseAdapter.SimpleAdapter和ArrayAdapter.其中常见的是BaseAdapter,也是个人推荐使用的适 ...
- android Activity类中的finish()、onDestory()和System.exit(0) 三者的区别
android Activity类中的finish().onDestory()和System.exit(0) 三者的区别 Activity.finish() Call this when your a ...
- Android应用如何支持屏幕多尺寸多分辨率问题
作为Android应用程序开发者都知道android是一个“碎片化”的世界.多种系统版本.多种尺寸.多种分辨率.多种机型,还有不同的厂商定制的不同ROM,你开发的应用会在不可预期的手机上报错.这给开发 ...
随机推荐
- [HDU5677]ztr loves substring
ztr loves substring Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- TortoiseSVN 和 VisualSVN Server 使用教程
TortoiseSVN 和 VisualSVN Server 使用教程 来源 https://blog.csdn.net/xgf415/article/details/75196360 目录: SVN ...
- PD模型创建完获取生成表脚本
1.双击表名,弹出属性对话框-->General----> Owner 表名前缀,如XX.SYS_TABLE 最好去掉 2.Preview 复制里面的脚本到数据库执行下即可
- 测试开发linux面试之三:后台进程之操作
Hi,大家好我是Tom,继上次分享之后这次给大家带来新的知识. 进程是Linux系统中一个非常重要的概念.Linux是一个多任务的操作系统,系统上经常同时运行着多个进程.我们不关心这些进程究竟是如何分 ...
- K8s仪表盘
{ "__inputs": [ { "name": "DS_TEST-ENVIORMENT-K8S", "label": ...
- [应用篇]第五篇 JSTL之fmt标签日期和数字格式化
fmt标签个人用的比较少,但是我还是在这里简单的留一下笔记,也是算是学习了一下!这样方便你们课设的时候能用的上,要学会进步的学习,不要停留! 引入该标签库的方法为: <%@ taglib pre ...
- [DeeplearningAI笔记]序列模型2.8 GloVe词向量
5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.8 GloVe word vectors GloVe词向量 Pennington J, Socher R, Mannin ...
- CentOS7.2下安装mongoDB3.2.8
最近在又在倒腾MongoDB,把安装配置的相关命令贴出来 1.下载 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70- ...
- 解决HTML5标签兼容的办法搜集
HTML5的语义化标签以及属性,可以让开发者非常方便地实现清晰的web页面布局,加上CSS3的效果渲染,快速建立丰富灵活的web页面显得非常简单. HTML5的新标签元素有: <header&g ...
- Spring整合JMS(三)——MessageConverter介绍(转)
*注:别人那复制来的 1.4 消息转换器MessageConverter MessageConverter的作用主要有两方面,一方面它可以把我们的非标准化Message对象转换成我们的目标Me ...