2011-05-16 52 views
20

我有以下类代表可触摸的视图并绘制滑动条。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_MOVEs然后收到ACTION_CANCEL并没有进一步的事件。

为什么会发生?我不想取消活动并使其保持拖动状态。

回答

21

ACTION_CANCEL发生在父视图接管其子视图的某个控件时。

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

  1. 您将在此处收到停机事件。
  2. down事件将由该视图组的一个子项处理,或者由您自己的onTouchEvent()方法处理;这意味着您应该实现onTouchEvent()以返回true,所以您将继续看到手势的其余部分(而不是查找父视图来处理它)。此外,从onTouchEvent()返回true,您将不会收到任何以下事件onInterceptTouchEvent()并且所有触摸处理必须发生在onTouchEvent()正常情况下。
  3. 只要你从这个函数返回false,每个下面的事件(直到并包括最后的up)将在这里首先被传递,然后被传递到目标的onTouchEvent()
  4. 如果你从这里返回true,您将不会收到任何下列事件:目标视图将收到相同的事件,而是用行动ACTION_CANCEL,和所有其他事件将被传递到您的onTouchEvent()方法,不再出现在这里
+0

我意识到,添加该组件的成PopupWindow,我怎么能拦截事件,让所有的人这只是发生去它的孩子? – 2011-08-16 18:05:03

+2

我意识到这是一个抓住我的事件的Horizo​​ntalScrollView。 – 2011-08-16 18:16:01

+1

https://www.youtube.com/watch?v=EZAoJU-nUyI 这可能是有帮助的 – kouretinho 2015-07-29 07:38:56

41

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

这对我有一个ViewPager与可滑动内容时的工作。内容没有收到水平滑动,因为它们被ViewPager拦截。我只是将对ViewPager的引用传递到子视图中,并且现在子对所有ACTION_DOWN事件调用mParent.requestDisallowInterceptTouchEvent(true)。 – OldSchool4664 2012-10-19 00:05:18

+0

如果您使用ViewPager,则应该使用ViewPager#canScroll(android.view.View,boolean,int,int,int)。 ViewPager的这种受保护的方法特别用于确定何时ViewPager应该滚动页面的内容或切换到下一页。 – Alexey 2012-11-26 13:15:13

+0

非常感谢你正在工作 – 2013-02-26 22:47:21