触摸时ACTION_CANCEL

时间:2011-05-16 13:41:15

标签: android events view touch

我有以下类来表示可触摸的视图并绘制幻灯片。

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而没有其他事件。

为什么会这样?我不想取消该事件并使其能够继续拖动。

3 个答案:

答案 0 :(得分:48)

当父容器拦截您的触摸事件时,会发生这种情况。任何覆盖ViewGroup.onInterceptTouchEvent(MotionEvent)的ViewGroup都可以这样做(例如ScrollView或ListView)。

处理此问题的正确方法是在您认为需要保留动作事件后在父视图上调用ViewParent.requestDisallowInterceptTouchEvent(boolean)方法。

这是一个快速示例(attemptClaimDrag方法取自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
    }
}

答案 1 :(得分:26)

当父视图接管其子视图之一时,会发生ACTION_CANCEL

查看ViewGroup.onInterceptTouchEvent(MotionEvent)方法的文档。从链接:

  1. 您将收到此次活动。
  2. 向下事件将由此视图组的子项处理,或者由您自己的onTouchEvent()方法处理;这意味着你应该实现onTouchEvent()以返回true,这样你将继续看到手势的其余部分(而不是寻找父视图来处理它)。另外,通过从onTouchEvent()返回true,您将不会在onInterceptTouchEvent()中收到任何后续事件,所有触摸处理必须在onTouchEvent()中正常发生。
  3. 只要您从此函数返回false,每个后续事件(包括最终版本)将首先在此处传递,然后传递到目标onTouchEvent()
  4. 如果您从此处返回true,则不会收到任何以下事件:目标视图将收到相同的事件但行动ACTION_CANCEL,并且所有其他事件将发送到您的onTouchEvent()方法,不再出现在这里

答案 2 :(得分:0)

另一种替代方法是: 您的ViewGroup中包含View

  1. ViewGroup的方法onInterceptTouchEvent()对于false返回ACTION_DOWN,在其他情况下返回true
  2. View总是以trueonTouch的形式返回onTouchEvent
  3. 用户邀请客人-ACTION_DOWNACTION_MOVE ...

因此,您将看到下一个流程

  1. ACTION_DOWN迭代:

    ViewGroup dispatchTouchEvent >start< ev = ACTION_DOWN
    ViewGroup onInterceptTouchEvent false
        View dispatchTouchEvent >start< ev = ACTION_DOWN
        View onTouch true
        View dispatchTouchEvent >finish< true
    ViewGroup dispatchTouchEvent >finish< true
    
  2. ACTION_MOVE迭代:

    ViewGroup dispatchTouchEvent >start< ev = ACTION_MOVE
    ViewGroup onInterceptTouchEvent true //<- start intercepting
        View dispatchTouchEvent >start< ev = ACTION_CANCEL //<- View is notified that control was intercepted
        View onTouch true
        View dispatchTouchEvent >finish< true
    ViewGroup dispatchTouchEvent >finish< true
    
  3. ACTION_MOVE迭代:

    ViewGroup dispatchTouchEvent >start< ev = ACTION_MOVE
    ViewGroup dispatchTouchEvent >finish< false
    

请看看diagram