ConstraintLayout的Barrier在RecyclerView部分ViewHolder中布局失效如何解决
问题根因
- 三个评分相关TextView的约束逻辑错误:
movie_rating_votes的start锚定到movie_rating的end,movie_votes的start锚定到movie_rating_votes的end,当被锚定的控件为GONE状态时,可见控件的水平约束失效,位置计算错误,进而导致关联的Barrier位置计算异常。 movie_rating_votes的可见性表达式存在笔误:当前写的是movie.rating != null && movie.rating != null,仅判断了rating不为空,没有校验votes是否存在,导致可见性逻辑不符合预期。- ViewHolder绑定数据时未立刻执行绑定:未调用
executePendingBindings(),DataBinding的更新会延迟到下一帧,此时RecyclerView已经完成了ViewHolder的布局测量,Barrier位置更新不及时,导致描述文本位置错乱。 - ConstraintLayout的Barrier默认会纳入GONE控件的位置计算,当三个控件中两个为GONE时,容易出现位置计算偏差。
修复步骤
1. 修正三个评分控件的约束
将三个TextView的start都统一约束到movie_image的end,因为同一时间只有一个可见,不会出现重叠问题,避免依赖其他同级别控件的位置:
<TextView android:id="@+id/movie_rating" ... app:layout_constraintStart_toEndOf="@id/movie_image" /> <TextView android:id="@+id/movie_rating_votes" ... app:layout_constraintStart_toEndOf="@id/movie_image" /> <TextView android:id="@+id/movie_votes" ... app:layout_constraintStart_toEndOf="@id/movie_image" />
2. 修复可见性表达式笔误
把movie_rating_votes的visible属性修正为同时判断rating和votes都不为空:
app:visible="@{movie.rating != null && movie.votes != null}"
3. 绑定数据时立刻执行绑定
在ViewHolder的bind方法中,赋值后调用executePendingBindings(),让布局立刻更新:
override fun bind(data: Movie, position: Int) { binding.movie = data binding.executePendingBindings() }
4. 优化Barrier配置(可选)
给Barrier添加barrierAllowsGoneWidgets="false"属性,让Barrier忽略GONE状态的控件,仅基于可见控件计算位置:
<androidx.constraintlayout.widget.Barrier android:id="@+id/movie_rating_votes_bottom_barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="bottom" app:barrierAllowsGoneWidgets="false" app:constraint_referenced_ids="movie_rating,movie_rating_votes,movie_votes" />
内容的提问来源于stack exchange,提问作者user924
相关产品推荐
相关产品推荐

