Skip to content

Commit 9490e17

Browse files
authored
Merge pull request #979 from RobbWatershed/drawer-fix
Minor fix for drawer swipe
2 parents c0d0773 + 0af86fd commit 9490e17

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

fastadapter-extensions-swipe/src/main/java/com/mikepenz/fastadapter/swipe/SimpleSwipeDrawerCallback.kt

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.mikepenz.fastadapter.swipe
22

3+
import android.annotation.SuppressLint
34
import android.graphics.Canvas
45
import android.graphics.Rect
56
import android.view.MotionEvent
@@ -29,10 +30,14 @@ class SimpleSwipeDrawerCallback @JvmOverloads constructor(private val swipeDirs:
2930
// Indicates whether the touchTransmitter has been set on the RecyclerView
3031
private var touchTransmitterSet = false
3132

32-
// States of swiped items
33-
// Key = item position
34-
// Value = swiped direction (see {@link ItemTouchHelper})
35-
private val swipedStates = HashMap<Int, Int>()
33+
/**
34+
* States of swiped items
35+
* Key = item unique ID
36+
* Value = swiped direction (see {@link androidx.recyclerView.widget.ItemTouchHelper})
37+
*
38+
* NB : As this class doesn't listen to the recyclerView, it may contain identifiers for old items that have been removed
39+
*/
40+
private val swipedStates = HashMap<Long, Int>()
3641

3742
// True if a swiping gesture is currently being done
3843
var isSwiping = false
@@ -108,9 +113,10 @@ class SimpleSwipeDrawerCallback @JvmOverloads constructor(private val swipeDirs:
108113

109114
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
110115
val position = viewHolder.adapterPosition
111-
if (position != RecyclerView.NO_POSITION && (!swipedStates.containsKey(position) || swipedStates[position] != direction)) {
116+
val id = viewHolder.itemId
117+
if (position != RecyclerView.NO_POSITION && (!swipedStates.containsKey(id) || swipedStates[id] != direction)) {
112118
itemSwipeCallback?.itemSwiped(position, direction)
113-
swipedStates[position] = direction
119+
swipedStates[id] = direction
114120
isSwiping = false
115121
}
116122
}
@@ -127,10 +133,11 @@ class SimpleSwipeDrawerCallback @JvmOverloads constructor(private val swipeDirs:
127133
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
128134
// During the "unswipe" gesture, Android doesn't use the threshold value properly
129135
// => Need to communicate an inverted value for swiped items
130-
return if (swipedStates.containsKey(viewHolder.adapterPosition)) 1f - surfaceThreshold
136+
return if (swipedStates.containsKey(viewHolder.itemId)) 1f - surfaceThreshold
131137
else surfaceThreshold
132138
}
133139

140+
@SuppressLint("ClickableViewAccessibility")
134141
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
135142
val itemView = viewHolder.itemView
136143

@@ -152,9 +159,9 @@ class SimpleSwipeDrawerCallback @JvmOverloads constructor(private val swipeDirs:
152159
val dXPercent = dX / recyclerView.width
153160

154161
// If unswiped, fire event and update swiped state
155-
if (0f == dX && swipedStates.containsKey(position)) {
162+
if (0f == dX && swipedStates.containsKey(viewHolder.itemId)) {
156163
itemSwipeCallback?.itemUnswiped(viewHolder.adapterPosition)
157-
swipedStates.remove(position)
164+
swipedStates.remove(viewHolder.itemId)
158165
}
159166

160167
// If the position is between "swiped" and "unswiped", then we're swiping
@@ -174,11 +181,17 @@ class SimpleSwipeDrawerCallback @JvmOverloads constructor(private val swipeDirs:
174181
* Android default touch event mechanisms don't transmit these events to the sublayer :
175182
* any click on the exposed surface just swipes the item back to where it came
176183
*/
184+
@SuppressLint("ClickableViewAccessibility")
177185
inner class RecyclerTouchTransmitter : View.OnTouchListener {
178186

187+
private var recyclerView: RecyclerView? = null
188+
179189
override fun onTouch(v: View?, event: MotionEvent): Boolean {
190+
// No need for that when nothing is swiped or when swiping is in progress
180191
if (isSwiping || null == v || v !is ViewGroup) return false
181192

193+
if (v is RecyclerView) recyclerView = v
194+
182195
// Get the first visible View under the clicked coordinates
183196
val childView = v.getFirstVisibleViewByCoordinates(event.x, event.y)
184197
// Transmit the ACTION_DOWN and ACTION_UP events to this View
@@ -198,6 +211,13 @@ class SimpleSwipeDrawerCallback @JvmOverloads constructor(private val swipeDirs:
198211
* Return the first visible non-ViewGroup View within the given ViewGroup, at the given coordinates
199212
*/
200213
private fun ViewGroup.getFirstVisibleViewByCoordinates(x: Float, y: Float): View? {
214+
215+
// If target viewHolder isn't swiped, don't bother going further
216+
if (this.parent == recyclerView) {
217+
val viewHolder = recyclerView?.getChildViewHolder(this)
218+
if (!swipedStates.containsKey(viewHolder?.itemId)) return null
219+
}
220+
201221
(childCount - 1 downTo 0)
202222
.map { this.getChildAt(it) }
203223
.forEach {

0 commit comments

Comments
 (0)