ConstraintLayout 1.1.0无法显示动态添加的自定义视图问题
你遇到的问题主要来自两个核心点:布局约束的错误配置,以及ConstraintLayout 1.1.0对约束规则的严格执行(1.0.2版本对这类错误的容错性更高),另外LayoutInflater的调用方式也需要优化,下面具体拆解:
1. 修复致命的布局约束错误
先看你的categoriesGridContainer布局代码:
<android.support.v7.widget.GridLayout android:id="@+id/categoriesGridContainer" ... app:layout_constraintTop_toBottomOf="@+id/categoriesContainer" />
这里的问题非常明显:categoriesGridContainer是categoriesContainer的直接子View,你却把它的顶部约束到了父容器的底部——等于直接把这个GridLayout放到了父容器的可视区域之外!
在ConstraintLayout 1.0.2中,这种错误约束可能被自动忽略或默认调整了,但1.1.0版本开始严格执行约束规则,导致GridLayout被移出父容器,再加上父容器是wrap_content,高度直接压缩为0,所以看起来是空的。
修复方式:把这个约束改成父容器的顶部对齐:
app:layout_constraintTop_toTopOf="parent"
修改后的categoriesGridContainer完整布局:
<android.support.v7.widget.GridLayout android:id="@+id/categoriesGridContainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" android:layout_marginTop="@dimen/tile_preview_margin_between_tiles" app:layout_constraintEnd_toEndOf="@+id/categoriesContainer" app:layout_constraintStart_toStartOf="@+id/categoriesContainer" app:layout_constraintTop_toTopOf="parent" />
2. 优化LayoutInflater的调用逻辑
你当前用inflater.inflate(R.layout.profile_category_inactive, null, false)加载自定义视图,这种方式会让视图丢失父容器的布局参数上下文,虽然你手动设置了GridLayout.LayoutParams,但在ConstraintLayout 1.1.0的环境下容易出现兼容性问题。
优化方式:传入父容器categoriesGridContainer作为inflate的第二个参数,第三个参数设为false(表示暂时不自动添加到父容器,我们后续手动调用addView):
// 替换原来的inflate调用 currentProfileCategoryActive = inflater.inflate(R.layout.profile_category_inactive, categoriesGridContainer, false); // 另一个分支同理修改 currentProfileCategoryActive = inflater.inflate(R.layout.profile_category_active, categoriesGridContainer, false);
这样LayoutInflater会根据父容器(GridLayout)的类型,为自定义视图生成正确的LayoutParams模板,后续你手动修改参数时会更稳定。
3. 额外检查项
- 确认
columnCount变量设置合理,比如2列/3列,保证动态添加的视图能正确排列; - 检查
AndroidUtil.dpToPx的实现是否正确,避免错误的宽度设置导致视图不可见; - 确认
marginBetweenTilesDp是合理的dp值,转换为px后不会导致视图被过度挤压。
按照上面的步骤修改后,升级到ConstraintLayout 1.1.0应该就能正常显示动态添加的视图了。
内容的提问来源于stack exchange,提问作者Alexei

