2011-05-16 55 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