扩展ConstraintLayout实现加载控件:ConstraintSet.applyTo致视图消失求助
解决ConstraintSet.applyTo()后视图消失的问题
嘿,我之前也踩过ConstraintSet的这个坑,咱们来一步步把它搞定~你遇到的核心问题是直接操作ConstraintSet而没有先克隆原布局的约束状态,导致apply后视图的visibility或布局参数被重置,最终无法显示。
问题根源分析
当你新建一个空的ConstraintSet并直接调用connect()设置约束时,它不会继承原布局中视图的任何状态(比如visibility默认是GONE),而且会覆盖掉原布局的所有约束,导致视图没有正确的布局规则,自然就不显示了。
完整解决方案
第一步:先写好自定义布局的XML
创建layout_loading_view.xml,定义半透明背景和居中的ProgressBar:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/loading_container" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 全屏半透明背景 --> <View android:id="@+id/loading_bg" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#80000000" android:visibility="gone"/> <!-- 居中的ProgressBar --> <ProgressBar android:id="@+id/loading_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone"/> </androidx.constraintlayout.widget.ConstraintLayout>
第二步:实现自定义ConstraintLayout类
关键是先克隆原布局的约束,再做修改,同时控制显示隐藏可以直接操作View(比用ConstraintSet更简单):
public class LoadingConstraintLayout extends ConstraintLayout { private View loadingBg; private ProgressBar loadingProgress; public LoadingConstraintLayout(Context context) { super(context); init(); } public LoadingConstraintLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public LoadingConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 加载布局到当前ConstraintLayout LayoutInflater.from(getContext()).inflate(R.layout.layout_loading_view, this, true); loadingBg = findViewById(R.id.loading_bg); loadingProgress = findViewById(R.id.loading_progress); // 如果你需要动态设置ProgressBar的居中约束(XML里没写的话) ConstraintSet constraintSet = new ConstraintSet(); // 先克隆当前布局的所有约束和状态!这一步是核心 constraintSet.clone(this); // 设置ProgressBar居中 constraintSet.connect(R.id.loading_progress, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0); constraintSet.connect(R.id.loading_progress, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 0); constraintSet.connect(R.id.loading_progress, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, 0); constraintSet.connect(R.id.loading_progress, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 0); // 应用约束 constraintSet.applyTo(this); } public void showLoading() { // 直接设置View可见,比用ConstraintSet更直观不容易出错 loadingBg.setVisibility(View.VISIBLE); loadingProgress.setVisibility(View.VISIBLE); } public void hideLoading() { loadingBg.setVisibility(View.GONE); loadingProgress.setVisibility(View.GONE); } }
关键注意点
- 必须先调用
constraintSet.clone(this):这会把当前布局中所有视图的约束、visibility、尺寸等属性复制到ConstraintSet中,后续的修改都是在这个基础上进行,不会丢失原有状态。 - 控制显示隐藏优先直接操作View:除非你需要同时调整约束,否则直接调用
View.setVisibility()比用ConstraintSet更简单,也避免了apply时的意外问题。 - 检查布局参数:确保自定义LoadingConstraintLayout在使用时的布局宽度和高度是
match_parent,否则半透明背景无法全屏。
内容的提问来源于stack exchange,提问作者Dannie
相关产品推荐
相关产品推荐

