Reputation: 11
I've made a simple class with gestures and I use it in a view.
I'm trying to do a simple swipe to dismiss effect but in the end, it's not that smooth. the translation is great but when the finger release happens, the velocity from the onFling function looks wrong..
class SwipeGestureListener : SimpleOnGestureListener, OnTouchListener {
var context: Context? = null
lateinit var flingDetector: GestureDetector
lateinit var flingY: FlingAnimation
lateinit var springBackTranslationYAnimation: SpringAnimation
var lastY = 0f
val minDistanceUp = 40
val friction = 0.1f
var minFlingArea = 0f
var isItUpDirection = false
constructor(
context: Context?,
dialog: View?
) {
this.context = context
dialog?.let {
it.viewTreeObserver
?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
minFlingArea = -(it.height + it.top).toFloat() - 100f
it.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
}
flingDetector = GestureDetector(context, flingListener)
springBackTranslationYAnimation = SpringAnimation(dialog,
object : FloatPropertyCompat<View>("translationY") {
override fun getValue(view: View): Float {
return view.translationY
}
override fun setValue(
view: View,
value: Float
) {
view.translationY = value
}
})
val springForceY = SpringForce(0f)
springForceY.stiffness = SpringForce.STIFFNESS_VERY_LOW
springForceY.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY
springBackTranslationYAnimation.spring = springForceY
springBackTranslationYAnimation.addUpdateListener(dynamicAnimationCallback())
flingY = FlingAnimation(dialog, DynamicAnimation.TRANSLATION_Y)
}
private val flingListener: GestureDetector.OnGestureListener =
object : SimpleOnGestureListener() {
override fun onDown(e: MotionEvent?): Boolean {
return true
}
override fun onFling(
downEvent: MotionEvent,
moveEvent: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
val distanceY = downEvent.rawY - moveEvent.rawY
if (distanceY >= minDistanceUp && isItUpDirection) {
flingY.setStartVelocity(if (velocityY > 0) -(velocityY) else velocityY)
.setMinValue(minFlingArea)
.setFriction(friction)
.start()
} else {
springBackTranslationYAnimation.start()
}
return true
}
}
override fun onTouch(view: View, event: MotionEvent): Boolean {
view.performClick()
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
flingY.cancel()
springBackTranslationYAnimation.cancel()
}
MotionEvent.ACTION_MOVE -> {
val deltaY = event.rawY - lastY
view.translationY = deltaY + view.translationY
isItUpDirection = event.rawY < lastY
}
MotionEvent.ACTION_UP -> {
if (!isItUpDirection) {
springBackTranslationYAnimation.start()
}
}
}
lastY = event.rawY
flingDetector.onTouchEvent(event)
return true
}
}
Any idea what's wrong here?
Thanks in advance!
Upvotes: 1
Views: 502
Reputation: 897
I have implemented gesture for swipe left and swipe right.Please try this one.
import android.content.Context
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
open class OnSwipeTouchListener(ctx: Context) : OnTouchListener {
val gestureDetector: GestureDetector
companion object {
private val SWIPE_THRESHOLD = 100
private val SWIPE_VELOCITY_THRESHOLD = 100
}
init {
gestureDetector = GestureDetector(ctx, GestureListener())
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
var isTouch = false
if (gestureDetector != null && event != null) {
isTouch = gestureDetector.onTouchEvent(event)
} else {
isTouch = true
}
return isTouch
}
inner class GestureListener : SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return false
}
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
var result = false
try {
val diffY = e1?.y?.let { e2?.y?.minus(it) }
val diffX = e1?.x?.let { e2?.x?.minus(it) }
if (diffX != null && diffY != null) {
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight()
} else {
onSwipeLeft()
}
result = true
}
} else {
}
} else {
onSwipeRight()
result = true
}
/*else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom()
} else {
onSwipeTop()
}
result = true
}*/
} catch (exception: Exception) {
exception.printStackTrace()
}
return result
}
}
open fun onSwipeRight() {}
open fun onSwipeLeft() {}
open fun onSwipeTop() {}
open fun onSwipeBottom() {}
open fun onSwipeDown() {
}
}
Call from your view
view?.setOnTouchListener(object : OnSwipeTouchListener(it) {
override fun onTouch(v: View, event: MotionEvent): Boolean {
return super.onTouch(v, event)
}
override fun onSwipeDown() {
super.onSwipeDown()
}
override fun onSwipeRight() {
}
override fun onSwipeLeft() {
super.onSwipeLeft()
}
}
}
}
}
Upvotes: 1