众所周知,在Android实际开发中,对于某些复杂多变的情况,控件的位置摆放、大小控制并非是xml类型的layout文件完全可以搞定的。此时,我们通常会使用Java代码来通过动态计算,将指定的控件摆放在相应的位置,并限定其大小。同样地,也需要获取某个控件的大小。

对于获取控件宽、高的方法,大家可以自行谷歌或者百度,大抵无非一下三种方法:

  1. 给相应的View控件添加ViewTreeObserver回调
  2. Override onWindowFocusChange方法
  3. 在需要测量时(而不是onCreate或onResume中),使用MeasureSpec内部类获取宽高。

对于上述第三种情况,我们暂且不论。对于前二者而言,有没有更简单的实现呢?

为何获取宽高要如此?

对于初学者,可能会有这样的疑问:为什么我们不能在onCreate()或者onResume()中直接使用上述第三种方案获取宽高呢?

结论是:那样的话,获取来的值很可能皆为0,即使实际的宽高不是0。那么这是为何呢?

这其实是由Android的UI绘制流程决定的。大家不妨试着做一下实验,即使是在onResume()方法后,它的意义也仅仅是指Activity进入了可见的状态,这并不意味着界面绘制的结束。我们可以用一个简单的带有宽高值得View来做实验,观察Activity中各回调方法的调用顺序,得到的结果将是这样的:

Activity.oncreate() → Activity.onResume() → View.onMeasure() → View.onLayout() → onGlobalLayoutListener() → Activity.onWidnowFocusChanged() → ... → View.onDraw() -> ...

因此,如果我们在onResume()中尝试获取View宽高的话,很大概率是会失败的。

巧用Handler获取View控件信息

这里我们开门见山地先放上代码片:

    private int[] measureView(final View view) {
final int[] returnData = new int[2];
view.post(new Runnable() {
@Override
public void run() {
returnData[0] = view.getWidth();
returnData[1] = view.getHeight();
Log.i(TAG, "Width: " + returnData[0] + ", height: " + returnData[1]);
}
});
return returnData;
}

上述代码作为通用的方法将获取任意View的宽高做了封装,其妙处就在‘view.post’处。

将其置于onCreate()、onResume()方法中调用,均可获取到正确的宽高。

	@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate start!");
setContentView(R.layout.activity_main);
testTv = (TextView) findViewById(R.id.testTv);
measureView(testTv);
} @Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume start!");
measureView(testTv);
}

Logcat中的运行结果:

2019-01-14 22:33:13.874 18355-18355/com.example.wenhan.helloandroid I/MainActivity: Width: 225, height: 57

2019-01-14 22:33:13.874 18355-18355/com.example.wenhan.helloandroid I/MainActivity: Width: 225, height: 57

为何如此就可获取到正确的值了呢?

其中的玄机在于,我们在View.post()中所写的语句并没有立即执行,而在其真正执行的时候,View的宽高已经被测量完成了,那时我们再去获取宽高时,就会很容易地获取到正确的值了。

通过断点Debug,可以轻松地发现,在Activity启动过程的调用栈中,存在ActivityThread类被执行了,具体按照:

main() -> handleResumeActivity() -> addView() -> setView() -> requestLayout() -> scheduleTraversals() -> 执行mTraversalRunnable异步线程 -> doTraversal() -> performTraversals() -> ... -> performMeasure() -> ...

的执行顺序。

在我们获取宽高的语句执行前,主线程的Handler正在执行TraversalRunnable(见上述方法具体实现),而performMeasure也被包含其中。又因为我们获取宽高的语句要排队,处于等待状态,直到主线程Handler轮到执行我们的语句,而此时View的宽高的测量已经结束。

完整示例代码: Github

巧用Handler获取View控件信息的更多相关文章

  1. appium获取APP控件信息

    uiautomatorviewer.bat 该文件位于SDK安装目录tools下,如笔者在“C:\Program Files (x86)\Android\android-sdk\tools”下,双击u ...

  2. Android自动化测试中AccessibilityService获取控件信息(1)

    Android自动化测试中AccessibilityService获取控件信息(1) 分类: android自动化测试2014-03-24 15:31 3455人阅读 评论(16) 收藏 举报 and ...

  3. UiAutomator源码分析之获取控件信息

    根据上一篇文章<UiAutomator源码分析之注入事件>开始时提到的计划,这一篇文章我们要分析的是第二点: 如何获取控件信息 我们在测试脚本中初始化一个UiObject的时候通常是像以下 ...

  4. C# 获取往控件中拖进的文件或文件夹的信息

    C# 获取往控件中拖进的文件或文件夹的信息(原创)       在做C#的WinForm开发的时候,有时需要用户往指定的控件中拖进文件或者文件夹.然后根据用户拖进来的文件或者文件夹获取其信息并进行下一 ...

  5. Android自动化测试中AccessibilityService获取控件信息(2)-三种方式对比

    Android自动化测试中AccessibilityService获取控件信息(2)-三种方式对比   上一篇文章: Android自动化测试中AccessibilityService获取控件信息(1 ...

  6. UiAutomator源代码分析之获取控件信息

    依据上一篇文章<UiAutomator源代码分析之注入事件>開始时提到的计划,这一篇文章我们要分析的是第二点: 怎样获取控件信息 我们在測试脚本中初始化一个UiObject的时候一般是像下 ...

  7. iOS开发UI篇—使用picker View控件完成一个简单的选餐应用

    iOS开发UI篇—使用picker View控件完成一个简单的选餐应用 一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162 ...

  8. 获取android控件的高度

    问题 如何获取一个控件的长和高,相信很多朋友第一眼看见这个问题都会觉得很简单,直接在onCreate里面调用getWidth.getMeasuredWidth不就可以获得了吗,但是,事实上是并没有简单 ...

  9. pywinauto如何获取gridwindow控件的屏幕位置

    一:问题描述 问题一:通过查找pywinauto在线文档,其中没有讲解到gridwindow控件的方法,我不知道这个控件是不是标准控件,还是pywinauto根本就没适配这个控件.从网上查询了好多资料 ...

随机推荐

  1. 学习CSS3之实心圆

    CSS3是最新版本的CSS,学习后可以更好的用于工作及自己修改自己代码的各种样式. border-radius圆角方法画实心圆.相当于在长方形(正方形)上画半径为边长一半的圆弧. 效果如上图,代码如下 ...

  2. CSharpGL(46)用Billboard绘制头顶文字

    CSharpGL(46)用Billboard绘制头顶文字 本文介绍CSharpGL用Billboard绘制头顶文字的方法.效果如下图所示. 下载 CSharpGL已在GitHub开源,欢迎对OpenG ...

  3. 《k8s-1.13版本源码分析》- Scheduler启动前逻辑

    本文原始地址(gitbook格式):https://farmer-hutao.github.io/k8s-source-code-analysis/core/scheduler/before-sche ...

  4. linux文件权限总结(创建root不可以删除文件、只可追加的日志文件等)

    文件类型 对于文件和目录的访问权力是根据读访问,写访问,和执行访问来定义的. 我们来看一下 ls 命令的输出结果 [root@iZ28dr6w0qvZ test]# ls -l 总用量 72 -rw- ...

  5. Data Lake Analytics的Geospatial分析函数

    0. 简介 为满足部分客户在云上做Geometry数据的分析需求,阿里云Data Lake Analytics(以下简称:DLA)支持多种格式的地理空间数据处理函数,符合Open Geospatial ...

  6. Visual Studio 2019 发布活动 - 2019 年 4 月 2 日

    Visual Studio 2019 发布活动 2019 年 4 月 2 日,星期二 | 上午 9:00 (PT) 围观: https://visualstudio.microsoft.com/zh- ...

  7. 设计模式之责任链模式——Java语言描述

    责任链模式为请求创建了一个接受者对象的链.这种模式给予请求的类型,对请求的发送者和接受者进行解耦.这种类型的设计模式属于行为模式.在这种模式下,通常每个接收者都包含对另一个接收者的引用.如果一个对象不 ...

  8. Odoo:全球第一免费开源ERP 人力资源模块操作指南(完美珍藏版)

    概述 人力资源管理概述 一般企业里,和人力资源相关的工作有:1)员工合同管理,即员工基本档案管理:2)招聘管理,即岗位及岗位人员补充管理:3)员工薪资计算: 4)员工考勤:5)员工休假管理:6)员工绩 ...

  9. Ocelot 资源汇总

    前言 最近一两年.NET Core的关注度持续上升, 微服务及云原生应用开发上采用.NET Core也越来越多,Ocelot 作为.NET Core平台下一款开源的API 网关开发库越来越得到社区的认 ...

  10. Php如何返回json数据,前后端分离的基本解决方案

    php返回json,xml,JSONP等格式的数据 返回json数据: header('Content-Type:application/json; charset=utf-8'); $arr = a ...