触摸时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而没有其他事件

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

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

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

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

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