使用 OnSwipeTouchListener 制作字母 L

Making the letter L with OnSwipeTouchListener

我在网上找到了一个很好的监听器 class 来制作一个 OnSwipeTouchListener。该侦听器可以确定用户何时向下、向上、向左或向右滑动:

public class OnSwipeTouchListener implements View.OnTouchListener {

    private GestureDetector gestureDetector;

    protected OnSwipeTouchListener(Context c) {
        gestureDetector = new GestureDetector(c, new GestureListener());
    }

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

    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) {
            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();
                        }
                    }
                } else {
                    if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffY > 0) {
                            onSwipeDown();
                        } else {
                            onSwipeUp();
                        }
                    }
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return false;
        }
    }

    public void onSwipeRight() {
    }

    public void onSwipeLeft() {
    }

    public void onSwipeUp() {
    }

    public void onSwipeDown() {
    }
}

我是这样使用它的:

findViewById(R.id.framelayout).setOnTouchListener(new OnSwipeTouchListener(this) {
            @Override
            public void onSwipeDown() {
                Toast.makeText(MainActivity.this, "Down", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSwipeLeft() {
                Toast.makeText(MainActivity.this, "Left", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSwipeUp() {
                Toast.makeText(MainActivity.this, "Up", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSwipeRight() {
                Toast.makeText(MainActivity.this, "Right", Toast.LENGTH_SHORT).show();
            }
        });

现在,我想添加函数onSwipeL()。这个函数是当用户用手指做出字母L时,就像onSwipeDown() + onSwipeRight()。

最好的方法是制作函数 onSwipeDoubleL()。这是用户用手指倒转双 L 的时候。就像同时制作 :

这可能吗?

有两种选择。

  • 首先 - 使用一些布尔值。 isSwipedRight(例如)。如果 isSwipedDown 为真,请检查 onSwipeRight(),如果是,则执行操作。在 onSwipeDown() 中将布尔值设置为 true,在所有其他(不包括向下)中设置为 false。
  • 创建你自己的onTouchListener 并自己测量距离。

我真的不明白你为什么需要这个手势。但这是我的解决方案。我们应该捕捉触摸事件,所以重写 onTouchEvent 方法。现在我们需要读取屏幕上的手指索引。

如果我们得到不止一次触摸,请为 X 坐标大于 "left finger" 的手指应用右食指。我不能说我是否找到了正确的索引。所以我检查索引坐标。

下一步我们保存起点并开始向下移动。如果我们在屏幕上有 2 个手指,请检查右手和左手手指,否则只有左手(或您希望的右手)。

如果我们在 "down" 距离大于最小值时捕获事件并开始移动到 left/right,我们需要保存新的起点以计算距离。

并等待用户移动到距离超过分钟的 left/right。最后用 "left" 和 "right" 手指检查是否成功或刚好离开(一触)。

我们还需要考虑移动时的不准确性(错误,错误)。用户不能向下或向左移动完全正确,因此解决方案高度依赖于此参数。您必须平衡范围和精度参数以舒适的手势控制。

代码未优化,仅展示基本思路。也许你会发现更多的小解决方案。对不起我的英语水平

public class MainMenuActivity extends AppCompatActivity {

    boolean movingDownL = false;
    boolean movingDownR = false;
    boolean movingLeft = false;
    boolean movingRight = false;

    boolean movingSuccessL = false;
    boolean movingSuccessR = false;

    // Deviation in pixels from the route (error value)
    int downInaccuracy = 30; // Down
    int lnrInaccuracy = 10; // Left and Right

    // Minimum distance to apply move (300 px in down and 100 to the left/right)
    int downMinDistance = 300;
    int lnrMinDistance = 50;

    Point oldCoordsL = new Point(0, 0); // Old coordinates left
    Point oldCoordsR = new Point(0, 0); // Old coordinates right
    Point startPointL = new Point(0, 0);
    Point startPointR = new Point(0, 0);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_menu);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int pIndexL = event.findPointerIndex(event.getPointerId(0));
        int pIndexR = 0;

        // If we have more than 1 touch read second finger index
        if(event.getPointerCount() > 1) pIndexR = event.findPointerIndex(event.getPointerId(1));

        // Check if we do not mistake when read fingers id
        if(event.getPointerCount() > 1 && event.getX(pIndexL) > event.getX(pIndexR)) {
            int tmp = pIndexR;
            pIndexR = pIndexL;
            pIndexL = tmp;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                movingDownL = true; // Start moving fingers
                movingDownR = true;
                movingSuccessL = false;
                movingSuccessR = false;

                // Get start point left and right if we need
                if(event.getPointerCount() > 1) {
                    startPointR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
                    oldCoordsR = new Point((int) event.getX(pIndexR), (int) event.getY(pIndexR));
                }

                startPointL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
                oldCoordsL = new Point((int) event.getX(pIndexL), (int) event.getY(pIndexL));
                break;
            case MotionEvent.ACTION_MOVE:
                // Add right finger handler
                if(event.getPointerCount() > 1) {
                    if(!movingDownR) {
                        // Check if we still moving to down
                        if(Math.abs(oldCoordsR.x - event.getX(pIndexR)) < downInaccuracy &&
                                oldCoordsR.y < event.getY(pIndexR)) break;
                        // Start moving to the right
                        if(Math.abs(oldCoordsR.y - event.getY(pIndexR)) < lnrInaccuracy &&
                                oldCoordsR.x > event.getX(pIndexR) && !movingRight) {
                            movingRight = true;
                            startPointR = new Point(new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR)));
                        }
                    }else {
                        if (Math.abs(oldCoordsR.x - event.getX(pIndexR)) > downInaccuracy ||
                                oldCoordsR.y < event.getY(pIndexR)) {
                            movingDownR = false;
                            break;
                        } else if(findDistance(startPointR,
                                new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= downMinDistance){
                            // Start moving to the left/right
                            movingDownR = false;
                        }
                    }
                }

                // Left finger handler by default even if we got only one touch
                // Check if we need move to any side
                if(!movingDownL) {
                    // Check if we still moving to down
                    if(Math.abs(oldCoordsL.x - event.getX(pIndexL)) < downInaccuracy &&
                            oldCoordsL.y < event.getY(pIndexL)) break;
                    // Start moving to the left
                    if(Math.abs(oldCoordsL.y - event.getY(pIndexL)) < lnrInaccuracy &&
                            oldCoordsL.x < event.getX(pIndexL) && !movingLeft) {
                        movingLeft = true;
                        startPointL = new Point(new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL)));
                    }
                }else {
                    if (Math.abs(oldCoordsL.x - event.getX(pIndexL)) > downInaccuracy ||
                            oldCoordsL.y > event.getY(pIndexL)) {
                        movingDownL = false;
                        break;
                    } else if(findDistance(startPointL,
                            new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= downMinDistance){
                        // Start moving to the left/right
                        movingDownL = false;
                    }
                }

                // Left move handler
                if(movingLeft) {
                    if (Math.abs(oldCoordsL.y - event.getY(pIndexL)) > lnrInaccuracy ||
                            oldCoordsL.x > event.getX(pIndexL)) {
                        movingLeft = false;
                        break;
                    } else if(findDistance(startPointL,
                            new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL))) >= lnrMinDistance) {
                        movingLeft = false;
                        movingSuccessL = true; // L from left finger is OK
                    }
                }

                // Right move handler
                if(movingRight) {
                    if (Math.abs(oldCoordsR.y - event.getY(pIndexR)) > lnrInaccuracy ||
                            oldCoordsR.x < event.getX(pIndexR)) {
                        movingRight = false;
                        break;
                    } else if(findDistance(startPointR,
                            new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR))) >= lnrMinDistance) {
                        movingRight = false;
                        movingSuccessR = true; // L from right finger is OK
                    }
                }

                if(movingSuccessL && movingSuccessR) {
                    Toast.makeText(this, "Yeah, it's look like double L", Toast.LENGTH_SHORT).show();
                } else if(movingSuccessL) Toast.makeText(this, "Yeah, it's look like L", Toast.LENGTH_SHORT).show();

                oldCoordsL = new Point((int)event.getX(pIndexL), (int)event.getY(pIndexL));
                oldCoordsR = new Point((int)event.getX(pIndexR), (int)event.getY(pIndexR));

                break;
            case MotionEvent.ACTION_UP:
                movingDownL = false;
                movingDownR = false;
                movingLeft = false;
                movingRight = false;
                break;
            default:
                return false;
        }

        return true;
    }

    private double findDistance(Point p1, Point p2) {
        return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
    }
}