2017-01-20 2 views
1

Я нашел хороший класс слушателя в Интернете, чтобы создать OnSwipeTouchListener. Этот слушатель может детерминированным, когда пользователь делает салфетки вниз, вверх, влево или вправо:Создание буквы L с помощью 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, перевернутый пальцами. Это как в то же время изготовления:

  • onSwipeDown() + onSwipeRight()
  • onSwipeDown() + onSwipeLeft()

Возможно ли это?

ответ

0

Я действительно не могу понять, зачем вам нужен этот жест. Но вот мое решение. Мы должны улавливать события касания, поэтому переопределяем метод onTouchEvent. Там нам нужно прочитать индекс пальцев, который на экране теперь.

Если мы получили более чем одно касание, примените правый указатель для пальца, который X координаты больше, чем «левый палец». Я не могу сказать, найду ли я правильные индексы. Поэтому я проверяю координаты индексов.

В следующем шаге мы сохраняем начальную точку и начинаем двигаться вниз. Если у нас есть 2 пальца на экране, проверьте правые и левые пальцы, остальные останутся (или вправо, как вы пожелаете).

Если мы поймаем событие, когда расстояние «вниз» больше минимального, и мы начинаем движение влево/вправо, нам нужно сохранить новую начальную точку, чтобы вычислить расстояние от нее.

И подождите, пока пользователь переместится влево/вправо с расстоянием больше мин. В конце концов проверьте успех «левым» и «правым» пальцами или просто слева (одним касанием).

Мы также должны думать о неточности (ошибки, ошибки) при перемещении. Пользователи не могут двигаться вниз или оставлять совершенно правильными, поэтому решение сильно зависит от этого параметра. Вы должны балансировать параметры диапазона и точности для удобства управления жестов.

Код не оптимизирован, показывается только основная идея. Возможно, вы найдете более мелкое решение. Извините за мой уровень Английский

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)); 
    } 
} 
+0

У меня есть сообщение «Да, это похоже на двойной L» все время, когда я касаюсь экрана. –

+0

Странно. Я тестировал приложение на двух устройствах, все работает нормально. Вы правильно скопировали мой код? Или что-то изменить?Он не может делать сообщения с сенсорным управлением, потому что moveSuccessL и movingSuccessR всегда ложны. –

+0

Теперь он работает извините. Проблема в том, что если я добавлю отладку в качестве примера, я вижу разное время моего отладки, когда я делаю двойной L. Это большая проблема, потому что после этого я должен вызвать фрагмент, а приложение вызывает разное время этого фрагмента. Как я могу позвонить только 1 раз? –

0

Существует два варианта.

  • Во-первых - используйте некоторые булевы. isSwipedRight (как пример). И проверьте onSwipeRight(), если isSwipedDown истинно, если да, то делайте что-нибудь. В onSwipeDown() установите boolean на true, а во всех остальных (исключая down) значение false.
  • Создайте свой собственный onTouchListener и измерьте расстояния самостоятельно.
Смежные вопросы