前言

日常开发中我们可能会遇到如下问题:

1、在onCreate\onStrart()\onResume()中获取View的宽高为0;
2、在onCreate\onStrart()\onResume()中直接调用Scroview.scrollTo(x,y)没有效果;

那么接下来一探究竟:

原因分析:

因为当onCreate()方法被调用的时候会通过LayoutInflater将xml文件填充到ContentView。
填充过程中只包括创建视图,不包括设置视图大小。而设置视图的大小和具体的位置则是通过布局层层遍历获得的。
如下图:

测量过程由measure(int , int)方法完成,该方法从上到下遍历视图树。在递归的过程中,每个视图都会向下层传递尺寸和规格,当measure方法遍历结束时,每个视图都保存了各自的尺寸信息。第二个过程由layout(int, int, int, int)方法完成,该方法也是由上而下遍历视图树。遍历过程中,每个父视图通过测量过程的结果定位所有姿势图的位置信息。

也就是说我们在onCreate\onStrart()\onResume()的时候我们并不知道什么时候布局测量完成,所以接下来我们去寻找一些方法。

解决方案:

###方案一:View.Post()/View.PostDelay() [重点]
我们先来看下源码:

/*** <p>Causes the Runnable to be added to the message queue.* The runnable will be run on the user interface thread.</p>** @param action The Runnable that will be executed.** @return Returns true if the Runnable was successfully placed in to the*         message queue.  Returns false on failure, usually because the*         looper processing the message queue is exiting.** @see #postDelayed* @see #removeCallbacks*/
public boolean post(Runnable action) {final AttachInfo attachInfo = mAttachInfo;if (attachInfo != null) {return attachInfo.mHandler.post(action);}// Postpone the runnable until we know on which thread it needs to run.// Assume that the runnable will be successfully placed after attach.getRunQueue().post(action);return true;
}

重点是这句话:The runnable will be run on the user interface thread
Runnable是一个接口,不是一个线程,一般线程会实现Runnable。所以如果我们使用匿名内部类是运行在UI主线程的,如果我们使用实现这个Runnable接口的线程类,则是运行在对应线程的。

也就是说我们用View.post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。
在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。
当Handler再次处理该Message时,已经在UI线程里,直接调用runnable的run方法。因此,我们可以毫无顾虑的来更新UI。

也就是说我们通过View.Post()/View.PostDelay()方法就可以实现获取view的宽高,并且Scroview.scrollTo(x,y)可以正常使用了。

view.post(new Runnable() {@Overridepublic void run() {//view的相关操作}
});

所以个人推荐使用View.post()既方便又可以保证指定的任务在视图操作中顺序执行。

方案二:onWindowFocusChanged

使用如下:

@Overridepublic void onWindowFocusChanged(boolean hasFocus) {//view的相关操作
}

我们看下官方注释:

/*** Called when the current {@link Window} of the activity gains or loses* focus.  This is the best indicator of whether this activity is visible* to the user.  The default implementation clears the key tracking* state, so should always be called.** <p>Note that this provides information about global focus state, which* is managed independently of activity lifecycles.  As such, while focus* changes will generally have some relation to lifecycle changes (an* activity that is stopped will not generally get window focus), you* should not rely on any particular order between the callbacks here and* those in the other lifecycle methods such as {@link #onResume}.** <p>As a general rule, however, a resumed activity will have window* focus...  unless it has displayed other dialogs or popups that take* input focus, in which case the activity itself will not have focus* when the other windows have it.  Likewise, the system may display* system-level windows (such as the status bar notification panel or* a system alert) which will temporarily take window input focus without* pausing the foreground activity.** @param hasFocus Whether the window of this activity has focus.** @see #hasWindowFocus()* @see #onResume* @see View#onWindowFocusChanged(boolean)*/
public void onWindowFocusChanged(boolean hasFocus) {
}

该方法会在view绘制完成之后调用,所以我们在这个时候去获取view宽高,或者Scroview.scrollTo(x,y)都可以正常运行了。
但是该方法如原注释所说,当Activity的窗口得到焦点和失去焦点时均会被调用一次,如果频繁地进行onResume和onPause,那么onWindowFocusChanged也会被频繁地调用。
所以也要结合具体业务场景。

方案三:ViewTreeObserver

使用ViewTreeObserver的众多回调可以完成这个功能,比如使用OnGlobalLayoutListener这个接口,当view树的状态发生改变或者view树内部的view的可见性发生改变时,onGlobalLayout方法将被回调,因此这是获取view的宽高一个很好的时机。需要注意的是,伴随着view树的状态改变等,onGlobalLayout会被调用多次。

view.getViewTreeObserver().addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() {@Overridepublic void onGlobalFocusChanged(View oldFocus, View newFocus) {//view的相关操作}
});

我们看一下View官方注释:

/*** A view tree observer is used to register listeners that can be notified of global* changes in the view tree. Such global events include, but are not limited to,* layout of the whole tree, beginning of the drawing pass, touch mode change....** A ViewTreeObserver should never be instantiated by applications as it is provided* by the views hierarchy. Refer to {@link android.view.View#getViewTreeObserver()}* for more information.*/
public final class ViewTreeObserver {//代码省略。。。
}

ViewTreeObserver这个类,这个类是用来注册当view tree全局状态改变时的回调监听器,这些全局事件包括很多,比如整个view tree视图的布局,视图绘制的开始,点击事件的改变等等。还有千万不要在应用程序中实例化ViewTreeObserver对象,因为该对象仅是由视图提供的。

综上,个人比较推荐方案一:View.Post()/View.PostDelay() 。

扫码关注公众号“伟大程序猿的诞生“,更多干货新鲜文章等着你~

公众号回复“资料获取”,获取更多干货哦~

有问题添加本人微信号“fenghuokeji996” 或扫描博客导航栏本人二维码

View.Post()保证UI带你装逼带你飞相关推荐

  1. 【带你装逼带你飞】吐血总结了这五大常用算法技巧,让你在同事/面试官面前惊艳全场!

    对于算法技巧,之前的文章也写过一些算法技巧,不过相对零散一些,今天我把之前的很多文章总结了下,并且通过增删查改,给大家总结一些常用的算法解题技巧,当然,这些也不是多牛逼的技巧,不过可以让你的代码看起来 ...

  2. js一些稀奇古怪的写法-带你装逼带你飞

    //定时器的第三个参数setInterval(function(str1,str2,num){alert(str1+str2+num)},1000,'参数1','还可以有很多参数,不同的类型...', ...

  3. vim带你装逼带你飞(一)

    前言:逃离windows有很长时间了,特别是当今android盛行的时代,我们没有理由不选择ubuntu作为编译开发android之首选.其实操作系统只是我们使用的一个工具, windows也好lin ...

  4. Retrofit2.0带你装逼,带你飞

    Retrofit2.0上手操作 retrofit简介 retrofit使用 retrofit简介 Retrofit是一款基于OKHttp的restful的网络请求框架.支持异步和同步请求,看到异步有么 ...

  5. 佳能桌面计算机,带你装Bee带你飞:Canon 佳能 X Mark I Keypad BT 计算器

    带你装Bee带你飞:Canon 佳能 X Mark I Keypad BT 计算器 2014-12-30 10:19:14 37点赞 93收藏 91评论 亲爱的张大妈家属大家好-好久不见还有人记得我吗 ...

  6. MySQL每秒57万的写入,带你装逼,带你飞 !!

    来源 | http://yq.aliyun.com/articles/278034 一.需求 一个朋友接到一个需求,从大数据平台收到一个数据写入在20亿+,需要快速地加载到MySQL中,供第二天业务展 ...

  7. 群晖NAS软件之:Drive你会用吗?带你装逼!

    原文网址:https://www.toutiao.com/a6664790105338675715/ 原作者:sabayonlinux 我的NAS我的地盘 篇六:群晖NAS软件介绍与应用之Drive篇 ...

  8. 零基础雪橇python_python零基础到项目实战-带你装b带你飞,带你冲刺年薪50万

    还有不知道Python是什么的看这里~敲黑板!! 近几年来,Python一直发展比较迅速,同时也受到了很多人的关注,对于IT行业的人来说,Python并不是很陌生,但是对于其他行业的来说,并不知道Py ...

  9. 如何打败理发店装逼洗剪吹小哥

    文 / ncieBIU (一) 话说周三晚上路过中关村,在商场转了一圈儿后打算回家.刚到地铁口,一个戴着黑框眼镜的小哥就把我拽住,问我对形象设计有没有什么想法.我表示没想法.他又说你知道xxx吗?这位 ...

  10. 小程序源码:简单舒服新UI装逼制作神器

    这是一款装逼神器小程序源码 内包含了N种模板制作,另外并有大分类 另外小编还给添加了几个流量主广告,包含了每一个页面都覆盖了 而且流量主还不是单一种: Banner 激励视频 视频广告 多格子广告 横 ...

最新文章

  1. python启动jupyter_如何在启动JupyterNotebook时自动执行代码?
  2. SpringBoot中常见的错误
  3. Docker的4种网络模式
  4. opencv 选择矩形框
  5. 知识点讲解七:Python中的异常处理机制
  6. python以下导入包的格式错误的是_ICMP python上的错误数据包
  7. [UE4] AnimationBlueprint: Node XXX uses potentially thread-unsafe call XXX 的解决办法,get 静态对象
  8. golang的channel机制
  9. 只属于你我的共同记忆
  10. php 百度天气,php使用百度天气接口示例
  11. IOUtils常用方法的使用
  12. java子类继承父类变量_JAVA子类继承父类
  13. word pdf 互转
  14. Janitor/Application Guarder
  15. 猪悟能淘宝商品下载专家v3版开发手记
  16. mysql增加重做日志组_mysql重做日志
  17. 暗影精灵 6 Plus 快速上手 大量游戏实测
  18. el-form 清除表单验证结果
  19. Learning and Meta-Learning of Stochastic Advection-Diffusion-Reaction Systems from Sparse Measuremen
  20. OSChina 周二乱弹 ——快晒晒你们公司的圣诞小姐姐啊!

热门文章

  1. css改火狐滚动条样式_自定义滚动条,可解决火狐滚动条默认样式修改不了问题...
  2. 数据结构_满二叉树、完全二叉树、二叉排序树、平衡二叉树
  3. SLAM学习与求职经验分享_李阳阳
  4. Python Revisited Day 09 (调试、测试与Profiling)
  5. 孩子们各显神通对付 iOS 12「屏幕使用时间」的限制
  6. 【aspnetcore】模拟中间件处理请求的管道
  7. BZOJ 1933 Bookcase 书柜的尺寸
  8. [django]自定义标签和过滤器
  9. js每隔5分钟执行一次ajax请求的实现方法
  10. Android7.0 MTK方案 静默安装和卸载