遗憾的是,解决这个问题的办法是将 ItemTouchHelper类的源代码复制到支持库中的同一个包中,并从 RecoverAnimation类中删除 mIsPendingCleanup属性。我不确定这是否被 Google 接受,我还没有把更新发布到 Play Store,看看它是否会导致拒绝,但是你可以找到来自支持库 v22.2.1的类源代码和上面提到的在 https://gist.github.com/kukabi/f46e1c0503d2806acbe2的修复。
@file:Suppress("PackageDirectoryMismatch")
package androidx.recyclerview.widget
import android.annotation.SuppressLint
/**
* [ItemTouchHelper] with recover viewHolder's itemView from clean up
*/
class RecoveredItemTouchHelper(callback: Callback, private val withRecover: Boolean = true) : ItemTouchHelper(callback) {
private fun recoverOnSwiped(viewHolder: RecyclerView.ViewHolder) {
// clear any swipe effects from [viewHolder]
endRecoverAnimation(viewHolder, false)
if (mPendingCleanup.remove(viewHolder.itemView)) {
mCallback.clearView(mRecyclerView, viewHolder)
}
if (mOverdrawChild == viewHolder.itemView) {
mOverdrawChild = null
mOverdrawChildPosition = -1
}
viewHolder.itemView.requestLayout()
}
@Suppress("DEPRECATED_IDENTITY_EQUALS")
@SuppressLint("VisibleForTests")
internal override fun postDispatchSwipe(anim: RecoverAnimation, swipeDir: Int) {
// wait until animations are complete.
mRecyclerView.post(object : Runnable {
override fun run() {
if (mRecyclerView != null && mRecyclerView.isAttachedToWindow
&& !anim.mOverridden
&& (anim.mViewHolder.absoluteAdapterPosition !== RecyclerView.NO_POSITION)
) {
val animator = mRecyclerView.itemAnimator
// if animator is running or we have other active recover animations, we try
// not to call onSwiped because DefaultItemAnimator is not good at merging
// animations. Instead, we wait and batch.
if ((animator == null || !animator.isRunning(null))
&& !hasRunningRecoverAnim()
) {
mCallback.onSwiped(anim.mViewHolder, swipeDir)
if (withRecover) {
// recover swiped
recoverOnSwiped(anim.mViewHolder)
}
} else {
mRecyclerView.post(this)
}
}
}
})
}
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val allowDelete = false // or show a dialog and ask for confirmation or whatever logic you need
if (allowDelete) {
adapter.remove(viewHolder.bindingAdapterPosition)
} else {
// start the inverse animation and reset the internal swipe state AFTERWARDS
viewHolder.itemView
.animate()
.translationX(0f)
.withEndAction {
itemTouchHelper.attachToRecyclerView(null)
itemTouchHelper.attachToRecyclerView(recyclerView)
}
.start()
}
}