8

メニューとしてを持っているアプリを開発してViewPagerいます。それぞれには、、 、 などfragmentの子ビューがたくさんあります。そのうちの 1 つには、設定パネル (ラッパー)といくつかの(ボタン) を子として切り替える設定ボタンがあります。この設定パネルは、上下にスライドするアニメーション (閉じたとき) でアニメーション化されており、表示されている場合はページングを無効にします。ListViewScrollViewLinearLayoutfragmentsLinearLayoutScrollViewLinearLayoutSeekBarViewPager

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (!pagingEnabled && event.getAction() == MotionEvent.ACTION_MOVE) {
        return true;
    }
    return super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (!pagingEnabled && event.getAction() == MotionEvent.ACTION_MOVE) {
        return true;
    }
    return super.onInterceptTouchEvent(event);
}

public boolean isPagingEnabled() {
    return pagingEnabled;
}

public void setPagingEnabled(boolean pagingEnabled) {
    this.pagingEnabled = pagingEnabled;
}

しかし、これには問題がありました。パネルが起動するたびに、すべての子ビューが を受信しないため、OnTouchEventを追加しましたGestureDetector.SimpleOnGestureListener:

protected class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        Log.i(C.TAG, "distanceX " + distanceX + " distanceY " + distanceY);
        return Math.abs(distanceY) < Math.abs(distanceX);
    }
}

そして私ViewPager onInterceptTouchEventを次のように変更しました:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (!pagingEnabled && event.getAction() == MotionEvent.ACTION_MOVE && (mGestureDetector != null && mGestureDetector.onTouchEvent(event))) {
        return true;
    }
    return super.onInterceptTouchEvent(event);
}

これは機能し、パネル ボタンは onClick や ListView スワイプなどを受け取りますが、それほどMath.abs(distanceY) < Math.abs(distanceX)正確ではないため、これは完璧には機能しません。上下または斜めにすばやくスワイプするか、マイナースワイプでボタンに触れると、onInterceptTouchEventも戻るtrueため、mGestureDetector.onTouchEvent(event)戻りtrueます。

いくつかのグーグル検索の後、私はこれに出くわしました:

viewPager.requestDisallowInterceptTouchEvent(true);

そして、私は次のようなことを試しました:

myListView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        viewPager.requestDisallowInterceptTouchEvent(true);
        return false;
    }
});

ViewPager.onInterceptTouchEventそして、それは最初に呼び出されMotionEvent.ACTION_DOWN、その後myListView.setOnTouchListenerすぐに呼び出され、残りのMotionEventアクション (MOVE および UP) を許可しないため、非常にうまく機能しViewPagerますListView

しかし、まだ問題が残っています。これrequestDisallowInterceptTouchEvent(true)をすべての子ビューに追加する必要onTouchEventがあり、エレガントなコードではありません。

だから私の質問は、私は正しい道を進んでいますか?このリスナーをすべてのパネルの子ビューに追加しないようにする方法はありますか (もちろん、必要な場合は最も一般的な方法で行います)。

御時間ありがとうございます。

4

2 に答える 2

25

ページングの無効化は、とfalseの両方から戻るのと同じくらい簡単です。を回避するために追加のジェスチャ検出は必要ありません。次のように拡張します。onInterceptTouchEventonTouchEventViewPagerViewPager

public class MyViewPager extends ViewPager {
    private boolean pagingEnabled = true;

    public MyViewPager(Context context) {
        super(context);
    }

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setPagingEnabled(boolean pagingEnabled) {
        this.pagingEnabled = pagingEnabled;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return pagingEnabled && super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return pagingEnabled && super.onTouchEvent(event);
    }

}

私のアプリの1つで同じ理由で同じもの(別の名前で)を使用していますが、間違いなく機能します。

于 2014-09-19T14:45:45.823 に答える