Open litao0621 opened 2 years ago
I made several changes based on MotionLayout.It worked for me right now
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.constraintlayout.motion.widget.MotionLayout
import kotlin.math.abs
/**
* @author : litao
* @email : onresume@live.com
* @date : 2022/5/31 5:31
*/
class TestMotionLayout constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
) : MotionLayout(context, attrs, defStyleAttr) {
private var mInitX = 0f
private var mInitY = 0f
private var mTouchSlop = 10
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
when (ev.actionMasked) {
MotionEvent.ACTION_DOWN -> {
mInitX = ev.x
mInitY = ev.y
}
MotionEvent.ACTION_MOVE -> {
val moveX = abs(ev.x - mInitX)
val moveY = abs(ev.y - mInitY)
if (moveX > mTouchSlop || moveY > mTouchSlop){
val obtain = MotionEvent.obtain(ev)
obtain.action = MotionEvent.ACTION_DOWN
dispatchTouchEvent(obtain)
onTouchEvent(obtain)
return true
}
}
MotionEvent.ACTION_UP -> {
}
}
return false
}
}
Could you please supply a better solution to this problem
Use this snippet if you place your carousel as a row item in a recyclerview.
override fun onInterceptTouchEvent(event: MotionEvent?): Boolean = true
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
previousX = event.x.toInt()
previousY = event.y.toInt()
hasActionMoveOccurred = false
}
MotionEvent.ACTION_UP -> {
disableTouchEventsForParent(false)
if (hasActionMoveOccurred.not()) {
onClick(carousel.currentIndex)
return true
}
}
MotionEvent.ACTION_MOVE -> {
val xDifferenceAbsolute = abs(calculateDistanceX(event))
val yDifferenceAbsolute = abs(calculateDistanceY(event))
hasActionMoveOccurred = xDifferenceAbsolute > scaledTouchSlop || yDifferenceAbsolute > scaledTouchSlop
if (isHorizontallyScrolling) {
return super.onTouchEvent(event)
}
val scrolledHorizontally = xDifferenceAbsolute > yDifferenceAbsolute
disableTouchEventsForParent(scrolledHorizontally)
}
}
return super.onTouchEvent(event)
}
private fun disableTouchEventsForParent(disable: Boolean) {
isHorizontallyScrolling = disable
parent.requestDisallowInterceptTouchEvent(disable)
}
private fun calculateDistanceX(currentMotionEvent: MotionEvent): Int = previousX - currentMotionEvent.x.toInt()
private fun calculateDistanceY(currentMotionEvent: MotionEvent): Int = previousY - currentMotionEvent.y.toInt()
You could do it like that, but if a user clicks while the "swipe motion" is in progress, it will trigger the onClick call on the old currentIndex of the carousel. So basically you can't differentiate which item was clicked.
Would be nice, if there was a ItemClickListener for the carousel. @jafu888
I am trying to figure out what sort of attribute we should add to enable the behavior you want. I do not want to modify the default behavior.
For Carousel index: I do not want to make assumptions on what is in the Carousel.
The simplest way to know what you clicked on is to setTag("MY_INDEX" , index) on the view in when populate it.
The easiest solution for now was to ignore clicks while the motionlayout is in transition.
Any updates on this issue. Please recommend any solution.
I'm having trouble adding an onClickListener to my carousel's items. I've tried setting the onClickListener in the adapter like so:
However, this makes the carousel unresponsive to swiping. When I try to swipe the carousel it executes my onClick function but doesn't execute my onSwipe transition.
Would really appreciate any help!