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

如何做到这一点?


当前回答

你不需要复杂的计算。 这可以通过使用来自GestureDetector类的OnGestureListener接口来完成。

在onFling方法中,你可以像这样检测所有四个方向:

MyGestureListener.java:

import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;

public class MyGestureListener implements GestureDetector.OnGestureListener{

    private static final long VELOCITY_THRESHOLD = 3000;

    @Override
    public boolean onDown(final MotionEvent e){ return false; }

    @Override
    public void onShowPress(final MotionEvent e){ }

    @Override
    public boolean onSingleTapUp(final MotionEvent e){ return false; }

    @Override
    public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
                        final float distanceY){ return false; }

    @Override
    public void onLongPress(final MotionEvent e){ }

    @Override
    public boolean onFling(final MotionEvent e1, final MotionEvent e2,
                       final float velocityX,
                       final float velocityY){

        if(Math.abs(velocityX) < VELOCITY_THRESHOLD 
                    && Math.abs(velocityY) < VELOCITY_THRESHOLD){
            return false;//if the fling is not fast enough then it's just like drag
        }

        //if velocity in X direction is higher than velocity in Y direction,
        //then the fling is horizontal, else->vertical
        if(Math.abs(velocityX) > Math.abs(velocityY)){
            if(velocityX >= 0){
                Log.i("TAG", "swipe right");
            }else{//if velocityX is negative, then it's towards left
                Log.i("TAG", "swipe left");
            }
        }else{
            if(velocityY >= 0){
                Log.i("TAG", "swipe down");
            }else{
                Log.i("TAG", "swipe up");
            }
        }

        return true;
    }
}

用法:

GestureDetector mDetector = new GestureDetector(MainActivity.this, new MyGestureListener());

view.setOnTouchListener(new View.OnTouchListener(){
    @Override
    public boolean onTouch(final View v, final MotionEvent event){
        return mDetector.onTouchEvent(event);
    }
});

其他回答

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

从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

这段代码检测左右滑动,避免了废弃的API调用,并对之前的答案进行了其他改进。

/**
 * Detects left and right swipes across a view.
 */
public class OnSwipeTouchListener implements OnTouchListener {

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener(Context context) {
        gestureDetector = new GestureDetector(context, new GestureListener());
    }

    public void onSwipeLeft() {
    }

    public void onSwipeRight() {
    }

    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_DISTANCE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceX > 0)
                    onSwipeRight();
                else
                    onSwipeLeft();
                return true;
            }
            return false;
        }
    }
}

像这样使用它:

view.setOnTouchListener(new OnSwipeTouchListener(context) {
    @Override
    public void onSwipeLeft() {
        // Whatever
    }
});

爱德华·布雷的回答在科特林的使用

 view.setOnTouchListener(object: OnSwipeTouchListener(this) {
      override fun onSwipeLeft() {
        super.onSwipeLeft()
      }
      override fun onSwipeRight() {
        super.onSwipeRight()
      }
    }
 )

如果你还需要处理点击事件,这里做一些修改:

public class OnSwipeTouchListener implements OnTouchListener {

    private final GestureDetector gestureDetector = new GestureDetector(new GestureListener());

    public boolean onTouch(final View v, final MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;


        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            result = onSwipeRight();
                        } else {
                            result = onSwipeLeft();
                        }
                    }
                } else {
                    if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffY > 0) {
                            result = onSwipeBottom();
                        } else {
                            result = onSwipeTop();
                        }
                    }
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }

    public boolean onSwipeRight() {
        return false;
    }

    public boolean onSwipeLeft() {
        return false;
    }

    public boolean onSwipeTop() {
        return false;
    }

    public boolean onSwipeBottom() {
        return false;
    }
}

以及示例用法:

    background.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View arg0) {
            toggleSomething();
        }
    });
    background.setOnTouchListener(new OnSwipeTouchListener() {
        public boolean onSwipeTop() {
            Toast.makeText(MainActivity.this, "top", Toast.LENGTH_SHORT).show();
            return true;
        }
        public boolean onSwipeRight() {
            Toast.makeText(MainActivity.this, "right", Toast.LENGTH_SHORT).show();
            return true;
        }
        public boolean onSwipeLeft() {
            Toast.makeText(MainActivity.this, "left", Toast.LENGTH_SHORT).show();
            return true;
        }
        public boolean onSwipeBottom() {
            Toast.makeText(MainActivity.this, "bottom", Toast.LENGTH_SHORT).show();
            return true;
        }
    });

这个问题仍然存在。添加以下类:

private class SwipeFirstTouchListener implements View.OnTouchListener {

    private final DirtyOnSwipeTouchListener swipe;
    private final View.OnTouchListener delegate;

    private SwipeFirstTouchListener(DirtyOnSwipeTouchListener swipe, View.OnTouchListener delegate) {
        this.swipe = swipe;
        this.delegate = delegate;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (!swipe.onTouch(v, event)) {
            // no a swipe, so lets try with the rest of the events
            return delegate.onTouch(v, event);
        }
        return false;
    }
}

and

private class DirtyOnSwipeTouchListener extends OnSwipeTouchListener {
    private boolean dirty = false;
    private OnSwipeTouchListener delegate;

    public DirtyOnSwipeTouchListener(Context ctx, OnSwipeTouchListener delegate) {
        super(ctx);

        this.delegate = delegate;
    }

    private void reset() {
        dirty = false;
    }

    public void onSwipeTop() {
        dirty = true;

        delegate.onSwipeTop();
    }

    public void onSwipeRight() {
        dirty = true;
        delegate.onSwipeRight();
    }

    public void onSwipeLeft() {
        dirty = true;
        delegate.onSwipeLeft();
    }

    public void onSwipeBottom() {
        dirty = true;
        delegate.onSwipeBottom();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        try {
            super.onTouch(v, event);

            return dirty;
        } finally {
            dirty = false;
        }

    }
};

还有一个在网上找到的课程:

public class OnSwipeTouchListener implements OnTouchListener {
    
    private static final String TAG = OnSwipeTouchListener.class.getName();

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener(Context ctx) {
        gestureDetector = new GestureDetector(ctx, new GestureListener());
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                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 if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        onSwipeBottom();
                    } else {
                        onSwipeTop();
                    }
                    result = true;
                }
            } catch (Exception exception) {
                Log.d(TAG, "Unexpected problem handling swipes, ignoring.", exception);
            }
            return result;
        }
    }

    public void onSwipeRight() {
        // Do nothing
    }

    public void onSwipeLeft() {
        // Do nothing
    }

    public void onSwipeTop() {
        // Do nothing
    }

    public void onSwipeBottom() {
        // Do nothing
    }
}

然后添加你自己的OnTouchListener和OnSwipeTouchListener,如下所示:

    DirtyOnSwipeTouchListener swipe = new DirtyOnSwipeTouchListener(this, new OnSwipeTouchListener(this) {
        public void onSwipeTop() {
            // your code here
        }

        public void onSwipeRight() {
            // your code here
        }

        public void onSwipeLeft() {
            // your code here
        }

        public void onSwipeBottom() {
            // your code here
        }
    });


    View.OnTouchListener toggleListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                // your code here

                return true;
            } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
                // your code here

                return true;
            }
            return false;
        }
    };

    SwipeFirstTouchListener swipeFirstTouchListener = new SwipeFirstTouchListener(swipe, toggleListener);

    myView.setOnTouchListener(swipeFirstTouchListener);