如何实现RecyclerView侧滑至删除按钮宽度后停止并保持状态
问题描述
将RecyclerView条目侧滑至最大距离后松开手指,期望黑色布局保持不动、红色删除按钮持续显示,但实际松开后黑色布局会变宽覆盖删除按钮。
相关代码
row_content.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="horizontal"> <LinearLayout android:background="#000000" android:id="@+id/whiteLayout" android:layout_height="300dp" android:layout_width="0dp" android:orientation="horizontal" android:outlineProvider="none" android:translationZ="10dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> </LinearLayout> <TextView android:background="#FE3B30" android:gravity="center_vertical" android:id="@+id/deleteButton" android:layout_height="0dp" android:layout_width="wrap_content" android:paddingLeft="22dp" android:paddingRight="22dp" android:text="Delete" android:textColor="#FFFFFF" android:textSize="18dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
SwipeHelper.java
public class SwipeHelper extends ItemTouchHelper.SimpleCallback { public SwipeHelper(int dragDirs, int swipeDirs) { super(dragDirs, swipeDirs); } @Override public boolean onMove( @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { return false; } @Override public void onSwiped( @NonNull RecyclerView.ViewHolder viewHolder, int direction) { } @Override public float getSwipeEscapeVelocity(float defaultValue) { return Float.MAX_VALUE; } @Override public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) { return 1; } @Override public void onChildDraw( @NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (dX >= 0) { super.onChildDraw( c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); return; } MainActivity.ContentViewHolder contentViewHolder = (MainActivity.ContentViewHolder) viewHolder; LinearLayout whiteLayout = contentViewHolder.getWhiteLayout(); TextView deleteButton = contentViewHolder.getDeleteButton(); ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) whiteLayout.getLayoutParams(); if (-dX >= deleteButton.getWidth()) { layoutParams.setMargins( layoutParams.leftMargin, layoutParams.topMargin, deleteButton.getWidth(), layoutParams.bottomMargin); whiteLayout.setLayoutParams(layoutParams); } else { layoutParams.setMargins( layoutParams.leftMargin, layoutParams.topMargin, (int) -dX, layoutParams.bottomMargin); whiteLayout.setLayoutParams(layoutParams); } } }
解决方案
核心问题是松开手指后,ItemTouchHelper会自动重置View的滑动状态,导致手动设置的margin被还原。按以下步骤修改:
- 添加状态记录变量
在SwipeHelper类中添加成员变量,记录布局是否完全展开、删除按钮宽度:
private boolean isExpanded = false; private int deleteBtnWidth = 0;
- 修改
onChildDraw逻辑,固定滑动状态
不再手动修改LayoutParams,而是通过控制dX参数固定滑动位置,让ItemTouchHelper保持最终状态:
@Override public void onChildDraw( @NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { MainActivity.ContentViewHolder contentViewHolder = (MainActivity.ContentViewHolder) viewHolder; LinearLayout whiteLayout = contentViewHolder.getWhiteLayout(); TextView deleteButton = contentViewHolder.getDeleteButton(); // 缓存删除按钮宽度,避免重复计算 if (deleteBtnWidth == 0) { deleteBtnWidth = deleteButton.getWidth(); } // 处理左滑逻辑 if (dX < 0) { // 已展开则固定dX值,保持删除按钮完全显示 if (isExpanded) { dX = -deleteBtnWidth; } else { // 限制最大滑动距离不超过删除按钮宽度,达到后标记展开状态 if (-dX >= deleteBtnWidth) { dX = -deleteBtnWidth; isExpanded = true; } } super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); return; } // 右滑时重置展开状态 if (dX >= 0) { isExpanded = false; super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } }
- 优化布局(可选)
将黑色布局的layout_width改为match_parent,滑动时视觉效果更稳定:
<LinearLayout android:background="#000000" android:id="@+id/whiteLayout" android:layout_height="300dp" android:layout_width="match_parent" android:orientation="horizontal" android:outlineProvider="none" android:translationZ="10dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> </LinearLayout>
内容的提问来源于stack exchange,提问作者msl12
相关产品推荐
相关产品推荐

