RecyclerView设置ItemDecoration后ViewHolder底部出现异常边距
问题描述
我尝试通过Item Decorations为水平排列的RecyclerView首项添加右侧边距、末项添加左侧边距。
首尾项的左右边距已经成功添加,但中间项底部出现了来源不明的多余边距。
相关代码
ItemDecoration实现代码
public class MapItemDecoration extends RecyclerView.ItemDecoration { private final int spacing; public MapItemDecoration(int spacing) { this.spacing = spacing; } @Override public void getItemOffsets(Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state ) { final int position = parent.getChildLayoutPosition(view); final int itemCount = state.getItemCount(); if (position == 0) { // 首项添加右侧边距 outRect.set(0, 0, spacing, 0); } else if (itemCount > 0 && position == itemCount - 1) { // 末项添加左侧边距 outRect.set(spacing, 0, 0, 0); } else { // 中间项添加左右两侧边距 outRect.set(spacing, 0, spacing, 0); } } }

初始ViewHolder布局代码
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/image" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintDimensionRatio="H,1:1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
RecyclerView初始化代码
adapter = new MapAdapter(listLocations, this); int spacing = SpacingUtils.convertIntToDP(this, 32); recyclerView.addItemDecoration(new MapItemDecoration(spacing)); recyclerView.setLayoutManager(new LinearLayoutManager( this, LinearLayoutManager.HORIZONTAL, false )); recyclerView.setAdapter(adapter);

我在ItemDecoration的getItemOffsets方法中已经把底部边距值设为0,为什么ViewHolder底部还是会出现多余边距?哪部分配置有错误?
问题补充
我尝试给ViewHolder内的ImageView设置固定dp宽度做测试:
修改后的ViewHolder布局
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/image" android:layout_width="150dp" android:layout_height="150dp" app:layout_constraintDimensionRatio="H,1:1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>

这个修改可以消除底部的多余边距,但我需要ImageView使用如下属性配置:
<ImageView android:id="@+id/image" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintDimensionRatio="H,1:1"
来实现ViewHolder随屏幕尺寸自适应缩放,希望找到不用给ImageView设置固定宽度的解决方案,比如通过父约束布局的百分比配置实现适配。
问题原因&解决方案
这个多余底部边距和ItemDecoration逻辑无关,问题出在ViewHolder根布局的宽度配置上:
- 你给水平滚动的RecyclerView的item根布局设置了
android:layout_width="match_parent",会让每个item的宽度强制等于RecyclerView本身的宽度。ConstraintLayout在计算0dp(match_constraint)宽度的ImageView尺寸时,会先按父布局全宽算出1:1比例的正方形高度,后续ItemDecoration添加的左右边距是在item测量完成后额外加的嵌入偏移,不会重新触发item内部的测量流程,最终就会出现底部多余空白。 - 改成固定宽度后问题消失,就是因为固定宽度下item测量时不会占满RecyclerView全宽,边距计算不会出现偏差。
要实现自适应正方形item、同时不出现底部多余边距,按如下修改即可:
- 把ViewHolder根布局的
android:layout_width="match_parent"改成android:layout_width="wrap_content" - 给ImageView添加底部约束
app:layout_constraintBottom_toBottomOf="parent",避免高度计算溢出 - 如果要按屏幕百分比控制item宽度,直接给ImageView加
app:layout_constraintWidth_percent属性设置宽度占比即可,不用写死固定dp值,ImageView保持0dp宽高、1:1比例就能随屏幕尺寸自适应。
修改后的ViewHolder布局参考:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/image" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintWidth_percent="0.7" <!-- 按需调整item占屏幕宽度的比例 --> app:layout_constraintDimensionRatio="H,1:1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
修改完成后原有ItemDecoration逻辑不需要调整,左右边距会正常生效,也不会再出现底部多余边距,ImageView会始终保持1:1正方形比例,随屏幕尺寸自动适配宽度。
内容的提问来源于stack exchange,提问作者WHOATEMYNOODLES
相关产品推荐
相关产品推荐

