Подтвердить что ты не робот

Переопределение onTouchEvent, конкурирующего с ScrollView

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

То, как я это делаю, довольно стандартно, поскольку я переопределяю onTouchEvent в своем CustomView и проверяю, касается ли пользователь касания внутри изображения и т.д.

Моя проблема возникает, когда я хочу разместить этот CustomView в ScrollView. Это работает, но ScrollView и CustomView, похоже, конкурируют за MotionEvents, т.е. Когда я пытаюсь перетащить изображение, оно либо перемещается вяло, либо свитки просмотра.

Я думаю, мне, возможно, придется расширить ScrollView, чтобы я мог переопределить onInterceptTouchEvent и сообщить ему, находится ли пользователь в пределах изображения, чтобы не прокручивать. Но потому, что ScrollView выше в иерархии, как бы получить доступ к текущему состоянию CustomView?

Есть ли лучший способ?

4b9b3361

Ответ 1

Обычно Android использует длительное нажатие, чтобы начать перетаскивание в таких случаях, поскольку оно помогает устранить неоднозначность, когда пользователь намеревается перетащить элемент или прокрутить контейнер элемента. Но если у вас есть однозначный сигнал, когда пользователь начинает перетаскивать элемент, попробуйте getParent().requestDisallowInterceptTouchEvent(true) из пользовательского представления, когда вы знаете, что пользователь начинает перетаскивать. (Документы для этого метода здесь.) Это предотвратит перехват событий ScrollView до конца текущего жеста.

Ответ 2

Ни одно из найденных решений не работает "из коробки" для меня, возможно, потому, что мой пользовательский вид расширяет Просмотр, а не ViewGroup, и поэтому я не могу реализовать onInterceptTouchEvent.

Также вызов getParent().requestDisallowInterceptTouchEvent(true) запускал NPE или вообще ничего не делал.

Наконец, вот как я решил проблему:
Внутри пользовательского вызова onTouchEvent requestDisallow..., когда ваше представление позаботится о событии. Например:

@Override
public boolean onTouchEvent(MotionEvent event) {
    Point pt = new Point( (int)event.getX(), (int)event.getY() );
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (/*this is an interesting event my View will handle*/) {
            // here is the fix! now without NPE
            if (getParent() != null) {
                getParent().requestDisallowInterceptTouchEvent(true);
            }

            clicked_on_image = true;
        }
    } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
        if (clicked_on_image) {
            //do stuff, drag the image or whatever
        }
    } else if (event.getAction() == MotionEvent.ACTION_UP) {
        clicked_on_image = false;
    }
    return true;
}

Теперь мое настраиваемое представление прекрасно работает, обрабатывает некоторые события и позволяет scrollView улавливать те, которые нам не нужны. Нашел решение здесь: http://android-devblog.blogspot.com.es/2011/01/scrolling-inside-scrollview.html

Надеюсь, что это поможет.

Ответ 3

Существует Android-событие под названием MotionEvent.ACTION_CANCEL (value = 3). Все, что я делаю, переопределяет мой настраиваемый метод onTouchEvent и фиксирует это значение. Если я обнаруживаю это условие, то я отвечаю соответствующим образом.

Вот какой код:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if(isTouchable) {
        int maskedAction = event.getActionMasked();         
        if (maskedAction == MotionEvent.ACTION_DOWN) {
            this.setTextColor(resources.getColor(R.color.octane_orange));
            initialClick = event.getX();
        } else if (maskedAction == MotionEvent.ACTION_UP) {
            this.setTextColor(defaultTextColor);
            endingClick = event.getX();
            checkIfSwipeOrClick(initialClick, endingClick, range);
        } else if(maskedAction == MotionEvent.ACTION_CANCEL)
            this.setTextColor(defaultTextColor);
    }
    return true;
}