【问题标题】:Custom view with onTouch doesn't fling smoothly使用 onTouch 的自定义视图不流畅
【发布时间】:2020-01-10 11:30:12
【问题描述】:

我用手势制作了一个简单的类,并在视图中使用它。

我正在尝试做一个简单的滑动来消除效果,但最后,它并不是那么顺利。 翻译很棒,但是当手指松开时,onFling 函数的速度看起来不对..

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
    }
}

知道这里有什么问题吗?

提前致谢!

【问题讨论】:

    标签: android gesture ontouchlistener onfling


    【解决方案1】:

    我已经实现了向左滑动和向右滑动的手势。请试试这个。

    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() {
    
     }
    }
    

    从你的角度打电话

         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()
    
    
                            }
    
                        }
                    }
                }
            }
    

    【讨论】:

    • 感谢您的发帖,但我们正在做几乎相同的事情,但方式不同。我还需要视图来翻译我已经在做的事情,但是在触摸释放时,投掷不能顺利进行。还忘了提一下,如果没有 onTouch - view translationY(从代码中排除),fling 会按预期工作。
    • 请在 GestureListener 类中取消注释代码并使用覆盖方法 onSwipeTop 和 onSwipeTop,它可能对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多