2011-05-16 16 views
20

Mam następującą klasę, która reprezentuje widok, który jest dotykalny i narysuj pasek przewijania.ACTION_CANCEL podczas dotykania

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; 
} 
} 

Ale podczas dotykania i przeciągając go, Otrzymuję ACTION_DOWN niektóre ACTION_MOVEs następnie otrzymać ACTION_CANCEL i dalsze wydarzenia.

Dlaczego tak się dzieje? Nie chcę anulować zdarzenia i umożliwić mu przeciąganie paska.

Odpowiedz

21

An ACTION_CANCEL dzieje się, gdy widok nadrzędny przejmie kontrolę nad jednym z jego widoków podrzędnych.

Zapoznaj się z dokumentacją dotyczącą metody ViewGroup.onInterceptTouchEvent(MotionEvent). Od linku:

  1. Będziesz otrzymywać zdarzenie w dół tutaj.
  2. Zdarzenie upuszczenia zostanie obsłużone przez potomka tej grupy widoków lub podane do własnej metody obsługi do obsługi onTouchEvent(); oznacza to, że powinieneś zaimplementować onTouchEvent(), aby zwrócić true, więc będziesz nadal widział resztę gestu (zamiast szukać widoku rodzica, aby go obsłużyć). Ponadto, zwracając wartość true z onTouchEvent(), nie będzie żadnych następujących zdarzeń w onInterceptTouchEvent() i wszystkie przetwarzanie dotykowe musi odbywać się w trybie onTouchEvent(), tak jak zwykle.
  3. Tak długo, jak zwracasz wartość false z tej funkcji, każde następne zdarzenie (do ostatecznej włącznie) zostanie dostarczone najpierw tutaj, a następnie do celu onTouchEvent().
  4. Jeśli return true stąd, że nie otrzyma żadnych następujące zdarzenia: widok cel otrzyma tę samą imprezę, ale z działaniem ACTION_CANCEL i wszystkich dalszych wydarzeń zostanie dostarczona do sposobu onTouchEvent() i nie pojawiają się tutaj
+0

zdałem sobie sprawę, że dzieje się tak dopiero po dodaniu tego składnika w PopupWindow, w jaki sposób można przechwycić zdarzenia i uczynić je wszystkie idź do jego dzieci? –

+2

Zdałem sobie sprawę, że jest HorizontalScrollView, który chwyta moje zdarzenia. –

+1

https://www.youtube.com/watch?v=EZAoJU-nUyI może to być pomocne – kouretinho

41

To się stanie, gdy kontener nadrzędny przechwyci zdarzenie dotykowe. Dowolna grupa View, która przesłania ViewGroup.onInterceptTouchEvent(MotionEvent), może to zrobić (ScrollView lub ListView dla instancji).

Właściwym sposobem radzenia sobie z tym problemem jest wywołanie metody ViewParent.requestDisallowInterceptTouchEvent(boolean) w widoku rodzica, gdy zachodzi podejrzenie, że należy zachować zdarzenie ruchu.

Oto krótki przykład (metoda attemptClaimDrag pochodzi z kodem źródłowym 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

To działało dla mnie, gdy miałem ViewPager z przesuwalną treścią. Treść nie otrzymała poziome przeciągnięcia, ponieważ zostały przechwycone przez ViewPager. Po prostu przekazałem odwołanie do ViewPager do widoku potomnego, a teraz dziecko wywołuje mParent.requestDisallowInterceptTouchEvent (true) dla wszystkich zdarzeń ACTION_DOWN. – OldSchool4664

+0

Jeśli korzystasz z ViewPagera, powinieneś raczej użyć ViewPager # canScroll (android.view.View, boolean, int, int, int). Ta chroniona metoda ViewPagera jest specyficznie określana za każdym razem, gdy ViewPager ma przewijać zawartość strony lub przechodzić do następnej strony. – Alexey

+0

dziękuję bardzo działa –

Powiązane problemy