2011-05-16 11 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は、親ビューがその子ビューの1つの制御を引き継いだときに発生します。

ViewGroup.onInterceptTouchEvent(MotionEvent)メソッドに関するドキュメントをご覧ください。リンクから:

  1. ここでダウンイベントが表示されます。
  2. downイベントは、このビューグループの子によって処理されるか、処理する独自のonTouchEvent()メソッドに与えられます。これは、onTouchEvent()をtrueに戻すよう実装する必要があることを意味します。そのため、ジェスチャの残りの部分を表示し続けます(親ビューを処理するのではなく)。また、onTouchEvent()からtrueを返すと、onInterceptTouchEvent()に次のイベントは表示されず、すべてのタッチ処理は通常のようにonTouchEvent()で行われなければなりません。
  3. この関数からfalseを返す限り、次の各イベント(最終的なものまで)が最初に配信され、次にターゲットのonTouchEvent()に配信されます。ターゲットビューは同じイベントを受信しますが、アクションACTION_CANCEL、およびすべてのさらなるイベントにごonTouchEvent()方法に配信し、もはやここ
  4. を表示されません:あなたはここからtrueを返した場合
  5. は、あなたが任意の次のイベントを受信しません
+0

は私がイベントをインターセプトし、それらのすべてを作ることができるか、PopupWindowにこのコンポーネントを追加するとき、これはのみ発生することを実現しましたそれは子供ですか? –

+2

私はそれが私のイベントをつかんでいるHorizo​​ntalScrollViewだと認識しました。 –

+1

https://www.youtube.com/watch?v=EZAoJU-nUyI – kouretinho

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

+0

ViewPagerを使用している場合は、代わりにViewPager#canScroll(android.view.View、boolean、int、int、int)を使用してください。 ViewPagerのこの保護されたメソッドは、ViewPagerがページの内容をスクロールしたり、次のページに切り替える必要があるときに、常に特定するために作成されます。 – Alexey

+0

どうもありがとうございます。 –

関連する問題