RecyclerView 条目滑动删除辅助类
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.MotionEvent
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.benefit.workbox.widget.R
class SwipeDeleteHelper(
private val context: Context,
private val recyclerView: RecyclerView,
private val itemWidthDp: Int = 88, // 删除区域宽度(dp)
private val revealThreshold: Float = 0.3f, // 显示删除图标的阈值比例
private val deleteIconResId: Int = R.drawable.svg_gray_delete, // 删除图标资源ID
private val backgroundColor: Int = Color.TRANSPARENT, // 背景颜色
private val onItemDeleteListener: (position: Int) -> Unit, // 删除回调
) {
private val itemWidthPx: Int
private var swipingViewHolder: RecyclerView.ViewHolder? = null
private var deleteAreaBounds: android.graphics.Rect? = null
init {
itemWidthPx = dpToPx(context, itemWidthDp)
setupSwipeToDelete()
setupTouchListener()
}
private fun setupSwipeToDelete() {
val simpleCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
private val background = ColorDrawable(backgroundColor)
private val deleteIcon = ContextCompat.getDrawable(context, deleteIconResId)
private val intrinsicWidth = deleteIcon?.intrinsicWidth ?: 0
private val intrinsicHeight = deleteIcon?.intrinsicHeight ?: 0
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder,
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// 不自动删除,由区域点击触发
}
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean,
) {
// 限制最大滑动距离
val limitedDx = -itemWidthPx.coerceAtMost(-dX.toInt()).toFloat()
// 计算滑动比例
val swipeProgress = Math.abs(limitedDx) / itemWidthPx
val itemView = viewHolder.itemView
val itemHeight = itemView.bottom - itemView.top
// 绘制删除背景(覆盖整个删除区域)
background.alpha = (255 * swipeProgress).toInt()
background.setBounds(
itemView.right - itemWidthPx,
itemView.top,
itemView.right,
itemView.bottom
)
background.draw(c)
// 保存删除区域的边界,用于点击检测
if (isCurrentlyActive) {
deleteAreaBounds = android.graphics.Rect(
itemView.right - itemWidthPx,
itemView.top,
itemView.right,
itemView.bottom
)
swipingViewHolder = viewHolder
}
// 只有当滑动超过阈值时才显示删除图标
if (swipeProgress >= revealThreshold) {
// 计算删除图标位置(在删除区域内居中)
val iconLeft = itemView.right - itemWidthPx + (itemWidthPx - intrinsicWidth) / 2
val iconRight = iconLeft + intrinsicWidth
val iconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
val iconBottom = iconTop + intrinsicHeight
deleteIcon?.setBounds(iconLeft, iconTop, iconRight, iconBottom)
deleteIcon?.draw(c)
}
// 移动内容视图
itemView.translationX = limitedDx
}
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
return 0.5f // 需要滑动超过一半才认为完成滑动
}
}
val itemTouchHelper = ItemTouchHelper(simpleCallback)
itemTouchHelper.attachToRecyclerView(recyclerView)
}
@SuppressLint("ClickableViewAccessibility")
private fun setupTouchListener() {
recyclerView.setOnTouchListener { _, event ->
handleTouchEvent(event)
false
}
}
private fun handleTouchEvent(event: MotionEvent) {
if (event.action == MotionEvent.ACTION_UP && swipingViewHolder != null && deleteAreaBounds != null) {
val viewHolder = swipingViewHolder!!
val bounds = deleteAreaBounds!!
// 检查触摸点是否在删除区域内
if (bounds.contains(event.x.toInt(), event.y.toInt())) {
val position = viewHolder.bindingAdapterPosition
if (position != RecyclerView.NO_POSITION) {
// 触发删除回调
onItemDeleteListener(position)
// 重置状态
swipingViewHolder = null
deleteAreaBounds = null
}
}
}
}
private fun dpToPx(context: Context, dp: Int): Int {
val density = context.resources.displayMetrics.density
return (dp * density).toInt()
}
}
使用方法
SwipeDeleteHelper(
context = this,
recyclerView = binding.rvList,
) { position ->
}