在onCreate中测量View组件宽高的方法

有时需要在onCreate中对View进行初始化时需要用到View的宽高,但往往通过getHight(),getWith()拿到的宽高都是0,那是因为View在这时候并没有真正绘制出来。

通过度娘查资料找到了一种可以在onCreate中获得View宽高的办法。

解决方案:

给View绑定一个监听器,当View要绘制的时候,会在绘制前调用监听器里的方法。

 //获取组件的观察者
        ViewTreeObserver vto = mKeyOne.getViewTreeObserver();
        //给观察者加上监听器,当View要被绘制的时候就会回调里面的方法
        vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                // hasMeasured 为标识符,我们要获得View的长宽只需要获取一次,如果不把标识符改过来那么就会容易造成资源浪费。
                if (hasMeasured == false){
                    //获取View的狂高
                    int h = mKeyOne.getHeight(); 
                    int w = mKeyOne.getWidth();
                    //获取完长宽后就把他设置为true那么上面的代码不会再执行。
                    hasMeasured = true;
                }
                return true;
            }
        });


对于 ViewTreeObserver想有更多了解的可以到这个博客参考:点击打开链接

内容概要:本文介绍了一个基于冠豪猪优化算法(CPO)的无人机三维路径规划项目,利用Python实现了在复杂三维环境中为无人机规划安全、效、低能耗飞行路径的完整解决方案。项目涵盖空间环境建模、无人机动力学约束、路径编码、多目标代价函数设计以及CPO算法的核心实现。通过体素网格建模、动态障碍物处理、路径平滑技术和多约束融合机制,系统能够在维、密集障碍环境下快速搜索出满足飞行可行性、安全性与能效最优的路径,并支持在线重规划以适应动态环境变化。文中还提供了关键模块的代码示例,包括环境建模、路径评估和CPO优化流程。; 适合人群:具备一定Python编程基础和优化算法基础知识,从事无人机、智能机器人、路径规划或智能优化算法研究的相关科研人员与工程技术人员,尤其适合研究生及有一定工作经验的研发工程师。; 使用场景及目标:①应用于复杂三维环境下的无人机自主导航与避障;②研究智能优化算法(如CPO)在路径规划中的实际部署与性能优化;③实现多目标(路径最短、能耗最低、安全性最)耦合条件下的工程化路径求解;④构建可扩展的智能无人系统决策框架。; 阅读建议:建议结合文中模型架构与代码示例进行实践运行,重点关注目标函数设计、CPO算法改进策略与约束处理机制,宜在仿真环境中测试不同场景以深入理解算法行为与系统鲁棒性。
<think>我们正在讨论的是在Activity中如何获取组件View测量后的度。根据引用[3]和引用[4],我们知道在onCreate()或onStart()中直接调用View.getHeight()或View.getWidth()通常返回0,因为此时View尚未完成测量。我们需要在视图完成测量后获取度。引用[4]提到了一种可靠的方式:使用ViewTreeObserver.OnGlobalLayoutListener,当视图树完成布局时会回调。另外,引用[1]和引用[2]也提供了其他方法,但引用[2]中的例子在onCreate中直接获取度是无效的。因此,在Activity中获取组件测量度的正确方法如下:方法一:使用ViewTreeObserver.OnGlobalLayoutListener步骤:1.获取目标ViewViewTreeObserver。2.添加OnGlobalLayoutListener监听器。3.在监听器的回调中,此时可以获取到View测量度,注意获取后移除监听器(避免重复回调)。方法二:在onWindowFocusChanged中获取当Activity的窗口获得焦点时(即用户可见时),View已经完成测量和布局,此时可以直接获取度。方法三:通过post(Runnable)将获取度的任务放到消息队列末尾,待View完成测量后执行。下面详细说明:###方法一:OnGlobalLayoutListener(推荐)```javaViewtargetView=findViewById(R.id.target_view);ViewTreeObservervto=targetView.getViewTreeObserver();vto.addOnGlobalLayoutListener(newViewTreeObserver.OnGlobalLayoutListener(){@OverridepublicvoidonGlobalLayout(){//移除监听器,避免多次回调if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN){targetView.getViewTreeObserver().removeOnGlobalLayoutListener(this);}else{targetView.getViewTreeObserver().removeGlobalOnLayoutListener(this);}//此时可以获取度intmeasuredHeight=targetView.getHeight();intmeasuredWidth=targetView.getWidth();//或者使用getMeasuredHeight(),但通常getHeight()即可(布局后度)}});```注意:在Activity的onCreate、onStart或onResume中都可以设置此监听。###方法二:在onWindowFocusChanged中获取```java@OverridepublicvoidonWindowFocusChanged(booleanhasFocus){super.onWindowFocusChanged(hasFocus);if(hasFocus){ViewtargetView=findViewById(R.id.target_view);intheight=targetView.getHeight();intwidth=targetView.getWidth();//注意:这个方法会在每次窗口获得焦点时调用(比如弹出对话框后再回来),所以可能需要判断是否第一次获取}}```###方法三:使用post(Runnable)```javaViewtargetView=findViewById(R.id.target_view);targetView.post(newRunnable(){@Overridepublicvoidrun(){intheight=targetView.getHeight();intwidth=targetView.getWidth();}});```原理:post(Runnable)会将任务添加到View的消息队列末尾,当View完成测量和布局后,会执行该任务。###注意事项1.获取的度是像素值(px)。2.如果View的可见性为GONE,则获取的度为0。3.在Activity的生命周期中,视图的测量和布局是在onResume之后完成的,所以在此之前直接获取度为0。4.如果View度会动态改变(例如数据加载后改变),则需要重新获取,可以再次使用上述方法。###引用说明上述方法参考了引用[4](使用OnGlobalLayoutListener)和引用[1](在窗口可见时获取)的思想,并结合了Android开发中的常用实践[^1][^4]。另外,引用[3]也说明了为什么在onStart()中获取不到度,因为此时View尚未完成测量[^3]。因此,我们应避免在以下生命周期方法中直接获取度:-onCreate()-onStart()-onResume()(直接获取可能还为0)而应使用上述回调方法。###示例代码(方法一)假设我们有一个TextView,id为text_view,我们需要在Activity中获取其测量后的度:```javapublicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);finalTextViewtextView=findViewById(R.id.text_view);ViewTreeObservervto=textView.getViewTreeObserver();vto.addOnGlobalLayoutListener(newViewTreeObserver.OnGlobalLayoutListener(){@OverridepublicvoidonGlobalLayout(){//移除监听器if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN){textView.getViewTreeObserver().removeOnGlobalLayoutListener(this);}else{textView.getViewTreeObserver().removeGlobalOnLayoutListener(this);}//获取度intheight=textView.getHeight();Log.d("MainActivity","Textviewheight:"+height);}});}}```这样,我们就可以在Activity中安全地获取到View测量度。§§相关问题§§1.为什么在Activity的onCreate中直接调用View.getHeight()返回0?2.除了上述方法,还有哪些方式可以获取View测量度?3.在Fragment中如何获取View测量度?4.View.getMeasuredHeight()和View.getHeight()有什么区别?</think>### Android Activity 获取视图测量度的方法 在 Android Activity 中获取组件测量后的度,需要确保在视图完成测量流程后才能正确获取。以下是几种可靠的方法: #### 1. 使用 `OnGlobalLayoutListener`(推荐) ```java View targetView = findViewById(R.id.your_view); ViewTreeObserver vto = targetView.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 移除监听避免重复调用 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { targetView.getViewTreeObserver().removeOnGlobalLayoutListener(this); } else { targetView.getViewTreeObserver().removeGlobalOnLayoutListener(this); } // 获取测量度 int measuredHeight = targetView.getHeight(); Log.d("ViewHeight", "Measured height: " + measuredHeight); } }); ``` **原理**: 当视图树完成全局布局时触发回调,此时所有视图已完成测量和布局[^4]。 **优点**:最可靠的方式,保证获取到准确度 **适用场景**:任何需要精确获取视图尺寸的情况 #### 2. 在 `onWindowFocusChanged()` 中获取 ```java @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { View targetView = findViewById(R.id.your_view); int height = targetView.getHeight(); // 此时度已可用 } } ``` **原理**: Activity 窗口获得焦点时视图已完成布局[^1]。 **优点**:简单直接,无需额外监听器 **注意**:此方法在每次窗口焦点变化时都会触发 #### 3. 使用 `post()` 延迟获取 ```java View targetView = findViewById(R.id.your_view); targetView.post(() -> { int height = targetView.getHeight(); // 在主线程消息队列完成后执行 }); ``` **原理**: 将任务加入主线程消息队列末尾,等待当前测量/布局完成[^3]。 **优点**:代码简洁,适用于简单场景 **缺点**:不保证100%准确,复杂布局可能仍需时间 --- ### 关键注意事项 1. **测量时机问题** 在 `onCreate()`/`onStart()` 中直接获取度通常为0,因为视图尚未完成测量[^3]。 ```java // 错误示例(在onCreate中获取度): protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); View view = findViewById(R.id.text_view); int height = view.getHeight(); // 返回0 } ``` 2. **度获取方法区别** - `getHeight()`:返回布局后的实际度(像素) - `getMeasuredHeight()`:返回测量阶段计算的度 - 两者通常在布局后相同,但在动画过程中可能不同 3. **动态度变化处理** 若视图度可能变化(如数据加载后),需重新注册监听: ```java view.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { int newHeight = bottom - top; }); ``` --- ### 完整示例代码 ```java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = findViewById(R.id.text_view); // 方法1:全局布局监听 textView.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 移除监听防止重复调用 textView.getViewTreeObserver().removeOnGlobalLayoutListener(this); logHeight("GlobalLayout", textView); } }); // 方法2:延迟post textView.post(() -> logHeight("Post Runnable", textView)); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { logHeight("WindowFocus", findViewById(R.id.text_view)); } } private void logHeight(String source, View view) { Log.d("HeightMeasurement", source + " | Height: " + view.getHeight() + " | MeasuredHeight: " + view.getMeasuredHeight()); } } ``` ### 各方法对比 | 方法 | 可靠性 | 调用时机 | 适用场景 | |--------------------------|--------|-----------------------|------------------------------| | OnGlobalLayoutListener | ★★★★★ | 布局完成后立即调用 | 需要精确度的关键操作 | | onWindowFocusChanged | ★★★★☆ | 窗口获得焦点时 | 简单场景,不频繁度获取 | | post()延迟执行 | ★★★☆☆ | 当前任务队列完成后 | 快速开发,非关键度获取 | | OnLayoutChangeListener | ★★★★☆ | 布局变化时实时触发 | 动态调整度的视图 | > **最佳实践**:对于关键业务逻辑(如依赖视图度的计算),推荐使用 `OnGlobalLayoutListener`;对于简单场景可使用 `post()` 或 `onWindowFocusChanged`。 [^1]: 通过视图测量获取状态栏度的方法 [^3]: View测量流程完成前无法获取度 [^4]: OnGlobalLayoutListener 监听布局完成
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值