web-dev-qa-db-ja.com

Android:ネストされたボトムシートのクリック/ドラッグタッチイベントの問題

ボトムシートが別のボトムシート内にネストされています(FrameLayoutsレイアウト動作を使用してBottomSheet

また、クリックリスナーがアタッチされた2つの「ピークビュー」(FrameLayouts)もあり、クリックするとそれぞれ下部のシートを展開します。

したがって、アプリには基本的に3つのメイン画面があります。 「メインコンテナー」、次に最初の「ボトムシート」はフルスクリーンで展開でき、最初のボトムシートの一番下は2番目のボトムシートで、これもフルスクリーンで展開できます。

問題:

ネストしたボトムシートの「コンテナー」ビューにRecyclerViewを追加すると、2番目のピークビュー(シート2ピーク)でドラッグが機能しなくなります。ピークビューClickListenerまたはを削除すると、RecyclerViewは問題なく動作するようです。

望ましい結果:

両方の下部シートはドラッグ可能なままで、ピークビューをクリックして親下部シートを展開できる必要があります。下のシートはネストされたスクロールに通常どおりに応答する必要があります。

ClickListenerを削除し、代わりにタッチジェスチャーを使用してみましたが、私が試したことは何も役に立たないようです。

設計サポートライブラリのv25.3.1を使用しています。この問題は、4.4.4ストックを実行しているGalaxy S4、および7.1.2ストックを実行しているNexus 6Pで再現できます。 (他に利用可能なデバイスはありません)。

さらに詳しく見てみたい人のために、githubにテストプロジェクトを作成しました: https://github.com/timusus/bottomsheet-test

レイアウトを示すスクリーンショットをいくつか示します。

123

レイアウト構造は次のようになります(わかりやすくするために一部のコードは省略しています)。

<CoordinatorLayout>

    <FrameLayout
        Android:id="@+id/mainContainer" 
        Android:layout_height="match_parent"/>

    <FrameLayout
        Android:id="@+id/sheet1" 
        Android:layout_height="match_parent"
        app:layout_behavior="CustomBottomSheetBehavior"
        app:behavior_peekHeight="64dp">

        <FrameLayout
            Android:id="@+id/sheet1Container"
            Android:layout_height="match_parent"/>

        <CoordinatorLayout>

        <FrameLayout
            Android:id="@+id/sheet2
            Android:layout_height="match_parent"
            app:layout_behavior="CustomBottomSheetBehavior"
            app:behavior_peekHeight="64dp">

            <FrameLayout
                Android:id="@+id/sheet2Container"
                Android:layout_height="match_parent">

                <!-- Problematic RecyclerView -->
                <RecyclerView 
                Android:layout_height="match_parent"/>

            </FrameLayout>

            <!-- Problematic Click Listener on this view -->
            <FrameLayout 
                Android:id="@+id/sheet2PeekView"
                Android:layout_height=64dp"/>

        </FrameLayout>

        </CoordinatorLayout>

        <FrameLayout
            Android:id="@+id/sheet1PeekView"
            Android:layout_height=64dp"/>

    </FrameLayout>
</CoordinatorLayout/>

CustomBottomSheetBehaviorBottomSheetBehaviorの単なるサブクラスであり、2番目のシートが展開またはドラッグされている場合、最初のシートがタッチイベントをインターセプトするのを防ぎます。これにより、最初のシートを折りたたむことなく、2番目のシートを「展開」から「折りたたみ」にドラッグできます。

public class CustomBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {

    private boolean allowDragging = true;

    public void setAllowDragging(boolean allowDragging) {
        this.allowDragging = allowDragging;
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (!allowDragging) {
            return false;
        }

        return super.onInterceptTouchEvent(parent, child, event);
    }
}

BottomSheetBehaviorのカスタマイズがこの問題に関連するとは思いませんが、完全を期すために、次のように使用しています。

FrameLayout sheet1 = (FrameLayout) findViewById(R.id.sheet1);
bottomSheetBehavior1 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet1);

FrameLayout sheet2 = (FrameLayout) findViewById(R.id.sheet2);
       bottomSheetBehavior2 = (CustomBottomSheetBehavior) BottomSheetBehavior.from(sheet2);
       bottomSheetBehavior2.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
           @Override
           public void onStateChanged(@NonNull View bottomSheet, int newState) {
                //If the second sheet is expanded or dragging, don't allow the first sheet to respond to touch events.
               if (newState == BottomSheetBehavior.STATE_EXPANDED || newState == BottomSheetBehavior.STATE_DRAGGING) {
                   bottomSheetBehavior1.setAllowDragging(false);
               } else {
                   bottomSheetBehavior1.setAllowDragging(true);
               }
           }

これがonInterceptTouchEventBottomSheet、内部のRecyclerViewView.ClickListener盗むタッチのネストされたスクロール処理に関係するのかどうかわからないようですイベント、上記の組み合わせ、またはその他すべて。

どんな助けでも大歓迎です。

10
Tim Malseed

[〜#〜]固定[〜#〜]

これがBottomSheetのonInterceptTouchEvent、内部のRecyclerViewのネストされたスクロール処理、View.ClickListenerによるタッチイベントの盗用、上記の組み合わせ、または他の何かと完全に関連しているのかどうか、私にはわからないようです。

上記のCustomBottomSheetBehaviorView.ClickListenerの組み合わせです。

問題はbottomSheetBehavior1getSheet2PeekViewをドラッグしているときにドラッグイベントを取っているため、タッチを検出しましたgetSheet2PeekViewのイベントとセットbottomSheetBehavior1ドラッグfalseおよびbottomSheetBehavior2true


解決

このコードを入力すると、問題が解決します。

findViewById(getSheet2PeekViewResId()).setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.e(TAG, "onTouch: ");
            bottomSheetBehavior1.setAllowDragging(false);
            bottomSheetBehavior2.setAllowDragging(true);
            return false;
        }
    });

Pull Requestも作成され、完全に機能する変更がリポジトリに作成されます。

14
N J