如何通过代码获取LinearLayout中指定索引的ProgressBar并设置进度?
解决LinearLayout中指定索引ProgressBar的获取与进度设置问题
问题背景
要实现类似Instagram Stories的顶部进度条效果:动态向LinearLayout中添加多个ProgressBar,之后能获取指定索引的ProgressBar单独设置进度和最大值,但当前代码运行后页面空白,无法实现预期效果。
错误原因
- 执行时机错误:
OnGlobalLayoutListener是异步回调,在它外部调用linearLayout.getChildCount()时,子控件还未被添加,直接获取索引1的控件会得到null,强转ProgressBar触发空指针异常,导致页面崩溃空白。 - 类型转换错误:
linearLayout.getChildAt(index)拿到的是你inflate的stories_progress布局根节点LinearLayout,不是里面的ProgressBar,直接强转必然报错。 - 冗余循环逻辑:循环里重复获取同一个索引的控件,完全没必要。
修正方案
- 将设置ProgressBar进度的代码移到
OnGlobalLayoutListener的onGlobalLayout方法内部,确保控件已经添加完成。 - 先获取目标索引对应的子LinearLayout,再通过
findViewById拿到其中的ProgressBar。 - 移除无用的循环,直接定位到目标索引的控件。
修正后的代码
添加并设置ProgressBar的核心代码
linearLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); linearLayout.removeAllViews(); int newWidth = linearLayout.getWidth() / 7; int newHeight = linearLayout.getHeight(); int i = 0; while (i < 7) { LinearLayout child = (LinearLayout) getLayoutInflater() .inflate(R.layout.stories_progress, linearLayout, false); LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams(); lp.width = newWidth; lp.height = newHeight; linearLayout.addView(child); i++; } // 控件已添加完成,获取索引1的ProgressBar并设置进度 if (linearLayout.getChildCount() > 1) { LinearLayout targetChildLayout = (LinearLayout) linearLayout.getChildAt(1); ProgressBar pg = targetChildLayout.findViewById(R.id.stories_progressBar_id); pg.setProgress(20); pg.setMax(100); } } });
stories_progress布局(保持不变)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="5dp"> <ProgressBar android:id="@+id/stories_progressBar_id" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> </ProgressBar> </LinearLayout>
Activity布局(保持不变)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/linear_layout_id" android:layout_width="match_parent" android:layout_height="30dp" android:orientation="horizontal" tools:context=".stories"> </LinearLayout>
额外优化建议
可以把添加的ProgressBar实例缓存到一个List<ProgressBar>中,后续直接通过列表索引获取,不用每次都从LinearLayout中查找,更高效:
// 定义成员变量 private List<ProgressBar> progressBarList = new ArrayList<>(); // 在onGlobalLayout中添加控件时缓存 LinearLayout child = (LinearLayout) getLayoutInflater() .inflate(R.layout.stories_progress, linearLayout, false); // ...设置布局参数 linearLayout.addView(child); ProgressBar pb = child.findViewById(R.id.stories_progressBar_id); progressBarList.add(pb); i++; // 后续获取时直接用列表 if (progressBarList.size() > 1) { ProgressBar targetPb = progressBarList.get(1); targetPb.setProgress(20); targetPb.setMax(100); }
内容的提问来源于stack exchange,提问作者Miguel Bets
相关产品推荐
相关产品推荐

