我希望我的应用程序能够识别用户在手机屏幕上从右向左滑动。

如何做到这一点?


当前回答

If you want to display some buttons with actions when an list item is swipe are a lot of libraries on the internet that have this behavior. I implemented the library that I found on the internet and I am very satisfied. It is very simple to use and very quick. I improved the original library and I added a new click listener for item click. Also I added font awesome library (http://fortawesome.github.io/Font-Awesome/) and now you can simply add a new item title and specify the icon name from font awesome.

这是github的链接

其他回答

因为这个问题有点老,很流行,我试图更新答案,并通过结合答案和评论中的多种建议来改进它。

从Java切换到Kotlin并使用一些Kotlin语法Eyecandy(主观) 使onswipe函数返回它们是否消耗了事件(ruX答案) 从if语句中移除结果赋值并删除变量(直接返回) 仅检测垂直和水平滑动的替代方案 只能检测上、下、右、左的选择。 为保持一致性(方向,而不是位置),将上下重命名为上下。

四个方向都刷:

open class OnSwipeTouchListener(val context: Context?) : OnTouchListener {
    companion object {
        private const val SwipeThreshold = 100
        private const val SwipeVelocityThreshold = 100
    }

    private val gestureDetector = GestureDetector(context, GestureListener())

    override fun onTouch(v: View, event: MotionEvent): Boolean {
        return gestureDetector.onTouchEvent(event)
    }

    open fun onSwipeRight(): Boolean { return false }
    open fun onSwipeLeft(): Boolean { return false }
    open fun onSwipeUp(): Boolean { return false }
    open fun onSwipeDown(): Boolean { return false }

    private inner class GestureListener : SimpleOnGestureListener() {
        override fun onDown(e: MotionEvent): Boolean {
            return true
        }

        override fun onFling(
            e1: MotionEvent,
            e2: MotionEvent,
            velocityX: Float,
            velocityY: Float,
        ): Boolean {
            try {
                val diffY = e2.y - e1.y
                val diffX = e2.x - e1.x

                if (abs(diffX) > abs(diffY)) {
                    if (abs(diffX) > SwipeThreshold && abs(velocityX) > SwipeVelocityThreshold) {
                        return when {
                            diffX > 0 -> onSwipeRight()
                            else -> onSwipeLeft()
                        }
                    }
                } else if (abs(diffY) > SwipeThreshold && abs(velocityY) > SwipeVelocityThreshold) {
                    return when {
                        diffY > 0 -> onSwipeDown()
                        else -> onSwipeUp()
                    }
                }
            } catch (exception: Exception) {
                exception.printStackTrace()
            }
            return false
        }
    }
}

用法:

myView.setOnTouchListener(object : OnSwipeTouchListener(context) {
            // Implement any function you need:
            override fun onSwipeUp(): Boolean {
                Toast.makeText(context, "UP", Toast.LENGTH_SHORT).show()
                return true
            }

            override fun onSwipeLeft(): Boolean {
                Toast.makeText(context, "LEFT", Toast.LENGTH_SHORT).show()
                return true
            }
        })

onFling()的替代方案

替代方案删除更多代码并重新排序检查。重新排序是没有必要的,但我认为它看起来更整洁,更容易理解。 代码将放在try括号中。用法保持不变,只是实现各自的onSwipe函数

水平

val diffY = e2。Y - e1。Y 返回if (abs(velocityY) > SwipeVelocityThreshold) { 当{ > SwipeThreshold -> onSwipeDown() diffY < - swipethreshold -> onSwipeUp() Else -> false } }其他false

垂直

val diffX = e2。X - e1。X 返回if (abs(velocityX) > SwipeVelocityThreshold) { 当{ > SwipeThreshold -> onSwipeRight() diffX < - swipethreshold -> onSwipeLeft() Else -> false } }其他false

一个方向

"up"的例子

val diffY = e2。Y - e1。Y 返回{ diffY < - swipethreshold -> onSwipeUp() Else -> false }

Additional Notes: In (ruX answer) they discussed removing onDown to also detect an onClickListener for the same view. However, when I removed onDown, the class did not work anymore. I don't exactly know why. I looked into the code of GestureDetector but it is very complex and the consequences of the return value of onDown seems to have some implications. So I left it in. Also, you can just use SimpleOnGestureListener.onSingleTapUp() just like you did onFling and create a onClick() function that is called there.

版本信息:

compileSdkVersion 31 minSdkVersion 24 targetSdkVersion 31

我知道从2012年开始有点晚了,但我希望它能帮助到一些人,因为我认为它比大多数答案都更短,更干净:

view.setOnTouchListener((v, event) -> {
        
int action = MotionEventCompat.getActionMasked(event);

switch(action) {
    case (MotionEvent.ACTION_DOWN) :
        Log.d(DEBUG_TAG,"Action was DOWN");
        return true;

    case (MotionEvent.ACTION_MOVE) :
        Log.d(DEBUG_TAG,"Action was MOVE");
        return true;

    case (MotionEvent.ACTION_UP) :
        Log.d(DEBUG_TAG,"Action was UP");
        return true;

    case (MotionEvent.ACTION_CANCEL) :
        Log.d(DEBUG_TAG,"Action was CANCEL");
        return true;

    case (MotionEvent.ACTION_OUTSIDE) :
        Log.d(DEBUG_TAG,"Movement occurred outside bounds " +
                "of current screen element");
        return true;

    default :
        return super.onTouchEvent(event);
}
    });

当然,你可以只留下相关的手势。

src: https://developer.android.com/training/gestures/detector

If you want to display some buttons with actions when an list item is swipe are a lot of libraries on the internet that have this behavior. I implemented the library that I found on the internet and I am very satisfied. It is very simple to use and very quick. I improved the original library and I added a new click listener for item click. Also I added font awesome library (http://fortawesome.github.io/Font-Awesome/) and now you can simply add a new item title and specify the icon name from font awesome.

这是github的链接

扩展Mirek的回答,当你想在滚动视图中使用滑动手势时。默认情况下,滚动视图的触摸监听器被禁用,因此滚动动作不会发生。为了解决这个问题,您需要重写Activity的dispatchTouchEvent方法,并在您完成自己的侦听器后返回该方法的继承版本。

为了对Mirek的代码做一些修改: 我在OnSwipeTouchListener中添加了一个gestureDetector getter。

public GestureDetector getGestureDetector(){
    return  gestureDetector;
}

在Activity中声明OnSwipeTouchListener作为类范围的字段。

OnSwipeTouchListener onSwipeTouchListener;

相应修改用法代码:

onSwipeTouchListener = new OnSwipeTouchListener(MyActivity.this) {
    public void onSwipeTop() {
        Toast.makeText(MyActivity.this, "top", Toast.LENGTH_SHORT).show();
    }
    public void onSwipeRight() {
        Toast.makeText(MyActivity.this, "right", Toast.LENGTH_SHORT).show();
    }
    public void onSwipeLeft() {
        Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
    }
    public void onSwipeBottom() {
        Toast.makeText(MyActivity.this, "bottom", Toast.LENGTH_SHORT).show();
    }
});

imageView.setOnTouchListener(onSwipeTouchListener);

并覆盖活动内部的dispatchTouchEvent方法:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev){
        swipeListener.getGestureDetector().onTouchEvent(ev); 
            return super.dispatchTouchEvent(ev);   
    }

现在滚动和滑动动作都可以工作了。

对@Mirek Rusin的回答做了一点修改,现在你可以检测多点触摸了。这段代码在Kotlin上:

class OnSwipeTouchListener(ctx: Context, val onGesture: (gestureCode: Int) -> Unit) : OnTouchListener {

private val SWIPE_THRESHOLD = 200
private val SWIPE_VELOCITY_THRESHOLD = 200

private val gestureDetector: GestureDetector

var fingersCount = 0

fun resetFingers() {
    fingersCount = 0
}

init {
    gestureDetector = GestureDetector(ctx, GestureListener())
}

override fun onTouch(v: View, event: MotionEvent): Boolean {
    if (event.pointerCount > fingersCount) {
        fingersCount = event.pointerCount
    }
    return gestureDetector.onTouchEvent(event)
}

private inner class GestureListener : SimpleOnGestureListener() {

    override fun onDown(e: MotionEvent): Boolean {
        return true
    }

    override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
        var result = false
        try {
            val diffY = e2.y - e1.y
            val diffX = e2.x - e1.x
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        val gesture = when (fingersCount) {
                            1 -> Gesture.SWIPE_RIGHT
                            2 -> Gesture.TWO_FINGER_SWIPE_RIGHT
                            3 -> Gesture.THREE_FINGER_SWIPE_RIGHT
                            else -> -1
                        }
                        if (gesture > 0) {
                            onGesture.invoke(gesture)
                        }
                    } else {
                        val gesture = when (fingersCount) {
                            1 -> Gesture.SWIPE_LEFT
                            2 -> Gesture.TWO_FINGER_SWIPE_LEFT
                            3 -> Gesture.THREE_FINGER_SWIPE_LEFT
                            else -> -1
                        }
                        if (gesture > 0) {
                            onGesture.invoke(gesture)
                        }
                    }
                    resetFingers()
                }
            } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                if (diffY > 0) {
                    val gesture = when (fingersCount) {
                        1 ->  Gesture.SWIPE_DOWN
                        2 -> Gesture.TWO_FINGER_SWIPE_DOWN
                        3 -> Gesture.THREE_FINGER_SWIPE_DOWN
                        else -> -1
                    }
                    if (gesture > 0) {
                        onGesture.invoke(gesture)
                    }
                } else {
                    val gesture = when (fingersCount) {
                        1 ->  Gesture.SWIPE_UP
                        2 -> Gesture.TWO_FINGER_SWIPE_UP
                        3 -> Gesture.THREE_FINGER_SWIPE_UP
                        else -> -1
                    }
                    if (gesture > 0) {
                        onGesture.invoke(gesture)
                    }
                }
                resetFingers()
            }
            result = true

        } catch (exception: Exception) {
            exception.printStackTrace()
        }

        return result
    }
}}

在姿态。SWIPE_RIGHT和其他是唯一的整数标识符的手势,我用它来检测一种手势在我的活动:

rootView?.setOnTouchListener(OnSwipeTouchListener(this, {
    gesture -> log(Gesture.parseName(this, gesture))
}))

这里的gesture是一个整型变量它包含了我之前传递的值。