获得 View 宽高的几种方法
2016-12-20 16:08
183 查看
(转载)http://blog.csdn.net/zhaizu/article/details/52159870
Activity / Fragment 的生命周期和 View 绘制过程的各个阶段是相互独立的,所以我们在 onCreate() 里面使用 getWidth()/getMeasuredWidth() 往往得到 0。
得到 View 宽高的正确方式有如下几种:
ViewTreeObserver.OnPreDrawListener;
ViewTreeObserver.OnGlobalLayoutChangeListener;
View.measure(int widthMeasureSpec, int heightMeasureSpec, );
自定义控件;
前两种方法都是采用回调的方式,优点是简单、百分百正确,缺点是某些场景下局限较多、作用有限。
第三种方法的原理是模拟 View 的 measure 过程,执行完 measure 过程后再调用 View.getMeasuredWidth() / View.getMeasuredHeight() 得到的即为所求,但是局限如下:
只适用于一次完成 measure 过程的 View,而无法完全适用于一次 measure 过程需要多次调用 measure() 方法的 View (如 RelativeLayout、TextView 以及使用 weight 属性的 LinearLayout 等);
需要使用 MeasureSpec.makeMeasureSpec(int size, int mode)拼接出 measure() 方法的参数;
对于更复杂的场景,建议使用第四种方法——自定义控件(甚至可以直接继承 ViewGroup),在 onMeasure() 方法里面获得子 View 的宽高。
此外,坊间流传的另一种方法:
2
3
4
5
6
7
1
2
3
4
5
6
7
这种方法确实有效,但是却很侥幸。
之所以有效,是因为主线程开始执行
1
告诉其他人:我要独占主线程,除非我做完事了,否则你们都得等着。
当 traversal 过程完成了,measure + layout + draw 过程都完成了,实际的宽高也都计算完毕。这个时候再执行 post 出去的消息,就能得到正确的宽高值。
这是一个很鸡贼的方法,不是系统预设的方式,所以不建议使用该方法。
参考文章
Droidcon 2015 / Layout Transversal on Android - Lucas Rocha
Activity / Fragment 的生命周期和 View 绘制过程的各个阶段是相互独立的,所以我们在 onCreate() 里面使用 getWidth()/getMeasuredWidth() 往往得到 0。
得到 View 宽高的正确方式有如下几种:
ViewTreeObserver.OnPreDrawListener;
ViewTreeObserver.OnGlobalLayoutChangeListener;
View.measure(int widthMeasureSpec, int heightMeasureSpec, );
自定义控件;
前两种方法都是采用回调的方式,优点是简单、百分百正确,缺点是某些场景下局限较多、作用有限。
第三种方法的原理是模拟 View 的 measure 过程,执行完 measure 过程后再调用 View.getMeasuredWidth() / View.getMeasuredHeight() 得到的即为所求,但是局限如下:
只适用于一次完成 measure 过程的 View,而无法完全适用于一次 measure 过程需要多次调用 measure() 方法的 View (如 RelativeLayout、TextView 以及使用 weight 属性的 LinearLayout 等);
需要使用 MeasureSpec.makeMeasureSpec(int size, int mode)拼接出 measure() 方法的参数;
对于更复杂的场景,建议使用第四种方法——自定义控件(甚至可以直接继承 ViewGroup),在 onMeasure() 方法里面获得子 View 的宽高。
此外,坊间流传的另一种方法:
view.post(new Runnable(){ @Override public void run() { int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); } });1
2
3
4
5
6
7
1
2
3
4
5
6
7
这种方法确实有效,但是却很侥幸。
之所以有效,是因为主线程开始执行
ViewRootImpl.scheduleTraversals()方法的时候,会被设置一个屏障(以下代码出自 API 23):
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();1
1
告诉其他人:我要独占主线程,除非我做完事了,否则你们都得等着。
当 traversal 过程完成了,measure + layout + draw 过程都完成了,实际的宽高也都计算完毕。这个时候再执行 post 出去的消息,就能得到正确的宽高值。
这是一个很鸡贼的方法,不是系统预设的方式,所以不建议使用该方法。
参考文章
Droidcon 2015 / Layout Transversal on Android - Lucas Rocha
相关文章推荐
- Android ViewTreeObserver使用总结及获得View高度的几种方法
- Android 几种获得view的宽和高的方法
- 获得 View 宽高的几种方法
- Nhibernate 对view 查询的几种方法
- php获得客户端ip的几种方法
- bcb中几种获得字符ascii码的方法
- java获得绝对路径 的几种方法
- 获得系统的位数(64 or 32)-几种方法
- 获得filter的CLSID的几种方法
- WindowsAPI详解——获得进程可执行文件路径的几种方法
- java获得绝对路径 的几种方法
- FormView控件的几种验证方法
- 获得伴奏的几种方法
- JAVA获得当前时间的几种方法
- 获得文件路径的几种方法
- 用户控件获得焦点的几种方法
- 几种获得中英文混合字符串长度方法的性能比较
- C#中获得当前执行文件相关信息的几种方法
- 几种获得spring里注册Bean的方法
- 在rcp中获得父Shell的几种方法