Android开发:绘制阶段后如何同时获取两个View的宽度?
Android中同时获取多个View绘制后宽度的最优方案
在开发场景中,我在onCreate里给view1和view2设置了动态边距(X为非静态值),导致它们的宽度会发生变化——直接在onCreate中调用getWidth()只能拿到未设置边距的初始宽度。之前了解到可以用View.post()获取单个View绘制完成后的宽度,但现在需要同时获取两个View的宽度代入同一个计算公式(用来给另一个TextView设置边距),目前有两种实现方式,下面分析哪种更优,以及提供更稳妥的替代方案。
现有两种实现方式
方式一:单次Post获取两个View宽度
view1.post(() -> { width1 = view1.getWidth(); width2 = view2.getWidth(); formula(width1, width2); });
方式二:嵌套Post获取宽度
view1.post(() -> { width1 = view1.getWidth(); view2.post(() -> { width2 = view2.getWidth(); formula(width1, width2); }); });
方案对比与最优选择
- 方式二更不可取:嵌套Post会让第二个Runnable被放到消息队列更靠后的位置,完全没必要——因为
View.post()的Runnable会在当前View完成测量、布局后执行,此时整个页面的布局流程已经完成,view2的宽度也已经确定,不需要再额外给view2发Post消息。 - 方式一可行,但有更稳妥的替代方案:虽然方式一能正常工作,但如果布局结构复杂(比如view1和view2属于不同布局分支,或存在异步布局场景),可以用
ViewTreeObserver.OnGlobalLayoutListener监听整个布局的完成事件,确保所有View都完成测量和布局后再获取宽度:
更优方案:监听全局布局完成事件
// 获取页面根布局(也可以用任意包含view1、view2的父布局) View rootView = findViewById(android.R.id.content); rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 必须移除监听,避免布局变化时重复触发 rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int width1 = view1.getWidth(); int width2 = view2.getWidth(); formula(width1, width2); } });
用Java 8 Lambda简化写法:
View rootView = findViewById(android.R.id.content); rootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> { rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int width1 = view1.getWidth(); int width2 = view2.getWidth(); formula(width1, width2); });
另外,View.postOnAnimation()也能达到类似效果,它会在下一帧动画执行前触发,但对于单纯获取宽度的需求,View.post()已经足够使用。
额外优化建议
你的formula方法是通过两个View的宽度之和给TextView设置上边距,其实可以考虑用ConstraintLayout的原生约束来实现,比如使用Barrier组件:
- 给view1和view2添加Barrier,设置Barrier的方向为右侧
- 让text1的上边距依赖这个Barrier的位置
这样布局系统会自动计算并更新边距,不需要手动编写代码获取宽度,更符合Android布局的最佳实践,也能避免潜在的布局时机问题。
内容的提问来源于stack exchange,提问作者sacacorchos
相关产品推荐
相关产品推荐

