如何编程设置ConstraintLayout的Gone Margin适配多视图隐藏场景
问题背景
4个视图通过ConstraintLayout垂直约束连接,从上到下依次为A、B、C、D,原有布局代码如下:
<include android:id="@+id/A" layout="@layout/search_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/dimen_16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_title" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/B" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginHorizontal="12dp" android:layout_marginTop="12dp" android:nestedScrollingEnabled="false" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/A" tools:itemCount="3" tools:listitem="@layout/item_layout" tools:visibility="visible" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/C" android:layout_width="@dimen/dimen_0dp" android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/dimen_16dp" android:layout_marginTop="12dp" android:drawableStart="@drawable/ic" android:drawablePadding="@dimen/dimen_6dp" android:fontFamily="@string/font_family_roboto_regular" android:text="@string/pb_tag_error_note" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/B" tools:visibility="visible" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/D" android:layout_width="@dimen/dimen_0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dimen_16dp" android:background="#11101010" android:fontFamily="@string/font_family_roboto_medium" android:paddingHorizontal="@dimen/dimen_16dp" android:paddingVertical="6dp" android:text="@string/text" android:textColor="@color/black" android:textSize="14sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/C" app:layout_goneMarginTop="@dimen/dimen_12dp" tools:visibility="visible" />
现有布局的表现:
- 仅C设为GONE时,D配置的
layout_goneMarginTop=12dp生效,叠加RecyclerView条目自带的4dp边距,D与B的间距为16dp,符合预期 - 当B、C同时设为GONE时,需求要求A与D的间距为24dp,目前通过代码动态修改D的约束绑定到A底部实现,希望找到不需要动态修改约束的纯布局方案。
解决方案
完全不需要动态修改约束,也不需要新增额外布局层级或虚拟控件,利用ConstraintLayout原生的goneMargin链式生效规则即可实现,只需要给C控件补充一行属性:
app:layout_goneMarginTop="@dimen/dimen_12dp"
原理说明
ConstraintLayout的goneMargin生效规则为:只有当控件对应方向上的直接约束目标为GONE状态时,该方向的goneMargin才会替代原margin参与布局计算,目标可见时goneMargin完全不生效。当多个连续约束的控件同时为GONE时,每个控件的goneMargin会逐个叠加计算坍缩点位置。
补充属性后三个场景的布局表现完全符合需求:
- B、C均可见:C的约束目标B可见,新增的
goneMarginTop不生效,所有原有margin逻辑保持不变,布局和原效果完全一致 - 仅C为GONE、B可见:C的约束目标B可见,C的
goneMarginTop不生效,C坍缩点落在B的底部位置;D的约束目标C为GONE,D的goneMarginTop=12dp生效,叠加RecyclerView条目自带4dp边距,D与B间距为16dp,和现有效果一致 - B、C均为GONE:B坍缩点落在A的底部位置;C的约束目标B为GONE,C的
goneMarginTop=12dp生效,C的坍缩点偏移到A底部往下12dp位置;D的约束目标C为GONE,D的goneMarginTop=12dp生效,最终D的位置落在A底部往下12dp+12dp=24dp位置,完全符合需求。
内容的提问来源于stack exchange,提问作者caffmaniac
相关产品推荐
相关产品推荐

