触摸时 ACTION_CANCEL

新手上路,请多包涵

我有以下类代表可触摸的视图并绘制滑动条。

 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 并且没有进一步的事件。

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

原文由 Marcos Vasconcelos 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 483
2 个回答

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

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

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

原文由 nicholas.hauschild 发布,翻译遵循 CC BY-SA 3.0 许可协议

当父容器拦截您的触摸事件时,就会发生这种情况。任何覆盖 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
    }
}

原文由 Alexey 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题