Like many others, I needed to have a RecyclerView (ViewPager2) within my cards. Here is how I worked around it.
Disable/Enable Horizontal Swiping
I needed to be able to conditionally disable and enable horizontal swiping of the cards based on events within an item. To do so, I had a listener that could be passed into the adapter upon creation.
interface MatchItemListener {
fun disableCardSwipe()
fun enableCardSwipe()
}
And here is the integration of this listener upon adapter creation. Notice we are disabling/enabling the horizontal scrolling in the CardStackLayoutManager assigned to our parent's layoutManager.
Now we need to intercept the touches in the child items to disable/enable horizontal swiping in the parent's CardStackLayoutManager.
First, create a custom ViewGroup. In this instance, mine is a ConstraintLayout. In this we are doing some collision detection to see if the touch occurred in the view where we want to scroll horizontally. If its within this view, we call the listener to disable horizontal card swiping, otherwise we enable it again.
class MatchItemContainer @kotlin.jvm.JvmOverloads constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
var listener: MatchItemListener? = null
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
val x = round(ev.x).toInt()
val y = round(ev.y).toInt()
if (isTouchInsideView(findViewById<ViewPager2>(R.id.carousel),x, y)) {
listener?.disableCardSwipe()
} else listener?.enableCardSwipe()
return super.dispatchTouchEvent(ev)
}
private fun isTouchInsideView(view: View, x: Int, y: Int): Boolean =
(x > view.left && x < view.right) &&
(y > view.top && y < view.bottom)
}
Setting Listener on Each Child
We can share the same listener on each of the children. When the adapter creates the ViewHolder or whatever mechanism you're using to inflate your layout into a view, we assign the listener to our custom ViewGroup.
Here is how I'm doing it (I'm using the FastAdapter library so its inflating a ViewBinding but the principle is the same).
Like many others, I needed to have a RecyclerView (
ViewPager2
) within my cards. Here is how I worked around it.Disable/Enable Horizontal Swiping
I needed to be able to conditionally disable and enable horizontal swiping of the cards based on events within an item. To do so, I had a listener that could be passed into the adapter upon creation.
And here is the integration of this listener upon adapter creation. Notice we are disabling/enabling the horizontal scrolling in the
CardStackLayoutManager
assigned to our parent'slayoutManager
.Intercepting Touches
Now we need to intercept the touches in the child items to disable/enable horizontal swiping in the parent's
CardStackLayoutManager
.First, create a custom
ViewGroup
. In this instance, mine is aConstraintLayout
. In this we are doing some collision detection to see if the touch occurred in the view where we want to scroll horizontally. If its within this view, we call the listener to disable horizontal card swiping, otherwise we enable it again.Setting Listener on Each Child
We can share the same listener on each of the children. When the adapter creates the
ViewHolder
or whatever mechanism you're using to inflate your layout into a view, we assign the listener to our customViewGroup
.Here is how I'm doing it (I'm using the
FastAdapter
library so its inflating aViewBinding
but the principle is the same).Hope this helps someone.