onTouch: обнаружить ACTION_UP, не блокируя другие сенсорные события - PullRequest
0 голосов
/ 13 сентября 2018

У меня есть пользовательский вид, который действует как кнопка.Я рисую весь холст сам.Теперь я делаю набросок, когда ACTION_DOWN, и удаляю его после ACTION_UP или ACTION_CANCEL.

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Log.e("test", "ACTION_DOWN");
            break;
        case MotionEvent.ACTION_UP:
            Log.e("test", "ACTION_UP");
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.e("test", "ACTION_CANCEL");
            break;
    }

    return true;
}

. Это может сработать для меня, за исключением того, что теперь он блокирует другой жест за этим видом, которыйобнаружение ACTION_MOVE (прокрутка влево).

Если я верну false, то это работает нормально, но теперь ACTION_UP не вызывается.

Я хочу позвонить ACTION_UP, если fingerотменено, но в противном случае события передаются.

1 Ответ

0 голосов
/ 13 сентября 2018

Вы пробовали переопределить dispatchTouchEvent?

https://developer.android.com/reference/android/view/View.html#dispatchTouchEvent(android.view.MotionEvent)

UPDATE:

Так что сенсорные события - это нечто чудовищное. Краткое изложение этого ...

  1. Сначала они всплывают из вашего корневого контейнера в вашей активности. Это делается путем вызова dispatchTouchEvent, а затем onInterceptTouchEvent при условии, что перехват не был заблокирован дочерним представлением.
  2. Если ни одно представление не перехватывает событие, оно будет пузыриться до конечного узла (такого как кнопка), где вызывается onTouch. Если узел не обрабатывает его (возвращает true), его родитель получает шанс и так далее.

Это означает, что вы можете использовать dispatchTouchEvent или onInterceptTouchEvent, чтобы шпионить за событиями касания без изменения поведения. Если вы на самом деле не собираетесь перехватывать событие, я предлагаю использовать dispatchTouchEvent, поскольку он гарантированно будет выполняться, тогда как перехват может быть заблокирован (пример: DrawerLayout будет перехватывать события касания у края, чтобы открыть ящик).

Итак, окончательный результат:

public class MyView extends Button {
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                Log.e("test", "ACTION_DOWN");
                break;
            case MotionEvent.ACTION_UP:
                Log.e("test", "ACTION_UP");
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.e("test", "ACTION_CANCEL");
                break;
        }
        return super.dispatchTouchEvent(event);
    }
}

UPDATE:

Извините, поэтому у меня почему-то сложилось впечатление (в основном из-за моего плохого чтения), что мы имеем дело с родителем. Вот что я бы сделал ...

Продолжайте реализовывать onTouch и возвращайте true, чтобы поглотить все события. Это означает, что любые сенсорные события, которые начинаются на вашем экране, будут уничтожены. Затем мы переместим точку в координатное пространство родителя и вручную передадим событие касания, оно будет выглядеть так в вашем пользовательском представлении ...

private boolean passingTouchEventToParent = true;
final private Rect hitRect = Rect();
@Override
public boolean onTouch(MotionEvent event) {
    // Handle your custom logic here

    final ViewParent viewParent = getParent();
    if (passingTouchEventToParent &&
            viewParent != null &&
            viewParent instanceof View) {
        // Gets this view's hit rectangle in the parent's space
        getHitRect(hitRect);
        event.offsetLocation((float) hitRect.left, (float) hitRect.top);
        passingTouchEventToParent = viewParent.onTouchEvent(event);
    }
    if (event.getActionMasked() == MotionEvent.ACTION_UP) {
        // Motion event finished, reset passingTouchEventToParent
        passingTouchEventToParent = true;
    }
    return true;
}
...