6

スワイプを検出したいSliderViewと呼ぶトップレベルのViewGroupがあります。これはほとんど機能していますが、奇妙な失敗が 1 つあります。

SliderView の本質は、onInterceptTouchEvent をオーバーライドし、ユーザーが実際にスワイプしたら「true」を返して、他のビューが MotionEvent を認識しないようにすることです。コードの一部を次に示します。

public class SliderView extends ViewGroup
{
  enum MoveState { MS_NONE, MS_HSCROLL, MS_VSCROLL };
  private MoveState moveState = MoveState.MS_NONE;

  ... other code ...

  public boolean onInterceptTouchEvent(MotionEvent e)
  {
    final int action = e.getAction();
    switch (action & MotionEvent.ACTION_MASK)
    {
      case MotionEvent.ACTION_DOWN:
        moveState = MoveState.MS_NONE;
        break;

      case MotionEvent.ACTION_MOVE:
        if (moveState == MoveState.MS_NONE)
        {
          if (motion is horizontal)
          {
            moveState = MoveState.MS_VSCROLL;
            return true;
          }
          else
            moveState = MoveState.MS_VSCROLL; // let child window handl MotionEvent
        }
        else if (moveState == MoveState.MS_HSCROLL)
          return true; // don't let children see motion event.
    }
    return super.onInterceptTouchEvent (e);
  }

  ... other code ...
}

私の SliderView (最も外側のビュー) は常にonInterceptTouchEvent を受け取る必要があることを理解しています。私のテストの 1 つで、最上位の子は ですが、次のケースではそうではないようです。

最上位の子が ScrollView の場合、onInterceptTouchEvent は ACTION_MOVE を取得し、私のコードは私が望むことを行います。最上位の子が LinearLayout である別のケースでは、時々失敗します。常に ACTION_DOWN を取得しますが、ユーザーが LinearLayout 内のウィジェットに触れた場合にのみ ACTION_MOVE を取得します。空白の領域に触れると、ACTION_DOWN のみが通過します。

失敗した場合のタッチが SliderView の外部で発生しているかのように動作することに注意してください。しかし、その場合、なぜ ACTION_DOWN イベントが発生するのでしょうか?

2 番目の注意: ScrollView のソース コードを見ると、"inChild" をチェックしていることがわかります。それが何のためにあり、どのように関連するのかはわかりません。

4

4 に答える 4

6

ここにuser123321の答えのため

onInterceptTouchEventは、親がonTouchEventから「true」を返す子ビューを持っている場合にのみ呼び出されます。子がtrueを返すと、親はそのイベントをインターセプトする機会があります

于 2013-01-15T06:37:33.880 に答える
1

Android 開発者のリファレンス ( http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent) ) から:

「2. ....また、onTouchEvent() から true を返すことにより、onInterceptTouchEvent() で後続のイベントを受信せず、すべてのタッチ処理が通常どおり onTouchEvent() で行われる必要があります。」

おそらく、あなたの onTouchEvent が常に true を返すためです..?

于 2013-06-01T04:40:00.793 に答える
0

onTouchEvent をインターセプトする場合、タッチを適切にインターセプトするために行うべきことが 2 つあります (その他はすべてデフォルトです)。

  1. onInterceptTouchEvent() で false を返す

    @Override
    public boolean onInterceptTouchEvent(MotionEvent me) {
        return false;
    }
    
  2. onTouchEvent() で true を返す

    @Override
    public boolean onTouchEvent(MotionEvent me) {
    
        switch (me.getAction()) {
        case MotionEvent.ACTION_DOWN:
            log("MotionEvent.ACTION_DONE");
            break;
        case MotionEvent.ACTION_MOVE:
            log("MotionEvent.ACTION_MOVE");
            break;
        case MotionEvent.ACTION_CANCEL:
            log("MotionEvent.ACTION_CANCEL");
            userActionDown = false;
            break;
        case MotionEvent.ACTION_UP:
            log("MotionEvent.ACTION_UP");
            break;
        }
    
        return true;
    }
    
  3. 次に、あなたの場合(およびその他)について。上記のように onTouchEvent() ですべての計算を行います。onInterceptTouchEvent() は、ACTION_DOWN に対して 1 回だけ呼び出されます。ただし、onTouchEvent は ACTION_DOWN イベントも取得するため、スーパーではなく、そこで true を返す必要があります。

onInterceptTouchEvent() の詳細については、http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent) を参照してください

ps - ここで質問するときは、何をしようとしているかの説明も書く必要があります。物事を行うためのはるかに優れた方法が見つかる可能性は十分にあります。ナビゲーションの場合、探している本当の答えはViewPagerです。それはうまく機能し、実装が非常に簡単です。また、Android が開発者に提供する他の簡単なナビゲーション パターンも確認してください: link .

于 2013-09-06T02:15:13.743 に答える