ACTION_CANCEL при касании - PullRequest
23 голосов
/ 16 мая 2011

У меня есть следующий класс, который представляет сенсорный вид и рисует слайд-бар.

public class SlideBar extends View {
private int progress;
private int max;

private Paint background;
private Paint upground;

private RectF bar;

private boolean firstDraw;

public SlideBar(Context context, AttributeSet attrs) {
    super(context, attrs);
    progress = 0;

    upground = new Paint();
    upground.setColor(Color.parseColor("#C2296C"));

    background = new Paint();
    background.setColor(Color.parseColor("#777777"));
}

private void onFirstDraw() {
    max = getWidth();
    bar = new RectF(0, 19, max, 21);
}

public void onDraw(Canvas canvas) {
    if (!firstDraw) {
        onFirstDraw();
        progress = max;
        firstDraw = true;
    }

    canvas.save();
    canvas.drawRoundRect(bar, 5, 5, background);
    canvas.drawCircle(progress, 20, 9, upground);
    canvas.restore();
}

public void setValue(int value) {
    progress = value;
}

public boolean onTouchEvent(MotionEvent evt) {
    System.out.println(evt.getAction());
    progress = (int) evt.getX();
    invalidate();
    return false;
}
}

Но при касании и перетаскивании я получаю ACTION_DOWN, некоторые ACTION_MOVE затем получают ACTION_CANCEL и никаких дальнейших событий.

Почему это происходит? Я не хочу отменять событие и включать его, чтобы продолжать перетаскивать панель.

Ответы [ 2 ]

49 голосов
/ 31 июля 2012

Это произойдет, когда родительский контейнер перехватит ваше сенсорное событие. Любая ViewGroup, которая переопределяет ViewGroup.onInterceptTouchEvent (MotionEvent) , может сделать это (например, ScrollView или ListView).

Правильный способ справиться с этим - вызвать метод ViewParent.requestDisallowInterceptTouchEvent (boolean) в родительском представлении, если вам нужно сохранить событие движения.

Вот краткий пример (метод tryClaimDrag взят из исходного кода Android):

/**
 * Tries to claim the user's drag motion, and requests disallowing any
 * ancestors from stealing events in the drag.
 */
private void attemptClaimDrag() {
    //mParent = getParent();
    if (mParent != null) {
        mParent.requestDisallowInterceptTouchEvent(true);
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        if (iWantToKeepThisEventForMyself(event)) {
            attemptClaimDrag();
        }
        //your logic here
    } else {
        //your logic here
    }
}
26 голосов
/ 16 мая 2011

ACTION_CANCEL происходит, когда родительское представление берет на себя управление одним из своих дочерних представлений.

Посмотрите документацию по методу ViewGroup.onInterceptTouchEvent (MotionEvent) .По ссылке:

  1. Вы получите здесь событие down.
  2. Событие down будет обработано либо дочерним элементом этой группы представлений, либо передано вашему собственному onTouchEvent()метод для обработки;это означает, что вы должны реализовать onTouchEvent() для возврата true, поэтому вы продолжите видеть остальную часть жеста (вместо того, чтобы искать родительское представление для его обработки).Кроме того, возвращая true из onTouchEvent(), вы не получите никаких следующих событий в onInterceptTouchEvent(), и вся обработка касания должна происходить в onTouchEvent(), как обычно.
  3. Пока вы возвращаете false из этой функциикаждое следующее событие (вплоть до финала) включается сначала здесь, а затем в onTouchEvent().
  4. цели. Если вы вернете истину отсюда, вы не получите никаких следующих событий: цельview получит то же событие, но с действием ACTION_CANCEL, и все дальнейшие события будут доставлены в ваш метод onTouchEvent() и больше не будут отображаться здесь
...