Android: проблема с событием касания вложенного нижнего листа при нажатии / перетаскивании

У меня есть нижний лист, вложенный в другой нижний лист (FrameLayouts с использованием поведения макета BottomSheet)

У меня также есть несколько «просмотров» (FrameLayouts), к которым прикреплены прослушиватели щелчков, чтобы раскрыть нижние листы соответственно при нажатии.

Таким образом, в приложении есть три основных экрана. «Основной контейнер», затем первый «нижний лист», который можно развернуть на весь экран, а затем внизу первого нижнего листа, является второй нижний лист, который также можно развернуть в полноэкранном режиме.

Проблема:

Когда я добавляю RecyclerView во вложенный нижний лист «контейнер», перетаскивание перестает работать для второго обзора (Sheet 2 Peek). Если я удалю обзор ClickListener или RecyclerView, все будет работать отлично.

Желаемый результат:

Оба нижних листа должны оставаться перетаскиваемыми, а обзорные панели должны иметь возможность щелкнуть, чтобы развернуть их родительский нижний лист. Нижний лист должен реагировать на вложенные прокрутки, как обычно.

Я попытался удалить ClickListener и использовать вместо этого сенсорные жесты, но ничего из того, что я пробовал, похоже, не помогает.

Я использую v25.3.1 из библиотеки поддержки дизайна, и я могу воспроизвести эту проблему на Galaxy S4 с версией 4.4.4 и Nexus 6P с версией 7.1.2. (У меня нет других доступных устройств).

Я также создал тестовый проект на github для всех, кто хочет поближе познакомиться: https://github.com/timusus/bottomsheet-test

Вот пара скриншотов, демонстрирующих макет:

1 2 3

Структура макета выглядит так (некоторый код для ясности опущен):

<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/>

CustomBottomSheetBehavior - это всего лишь простой подкласс BottomSheetBehavior, который не позволяет первому листу перехватывать события касания, если второй лист разворачивается или перетаскивается. Это позволяет перетаскивать второй лист из «развернутого» в «свернутый» без одновременного свертывания первого листа.

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

Кажется, я не могу понять, связано ли это с onInterceptTouchEvent из BottomSheet, вложенной обработкой прокрутки внутренних событий касания RecyclerView, View.ClickListener кражи, комбинацией вышеперечисленного или чем-то еще.

Любая помощь приветствуется.


person Tim Malseed    schedule 02.05.2017    source источник
comment
добавление CustomBottomSheetBehavior через xml; вызывая ошибку. Как я могу предоставить myCustomBottomSheetBehavior через xml?   -  person Gentle    schedule 22.06.2018


Ответы (1)


ИСПРАВЛЕНО

Я не могу понять, связано ли это с onInterceptTouchEvent из BottomSheet, вложенной обработкой прокрутки внутреннего RecyclerView, событиями касания кражи View.ClickListener, комбинацией вышеперечисленного или чем-то еще.

Это комбинация вышеупомянутых CustomBottomSheetBehavior и View.ClickListener

Проблема заключалась в том, что bottomSheetBehavior1 принимает событие перетаскивания при перетаскивании getSheet2PeekView, поэтому определите событие касания в getSheet2PeekView и установите bottomSheetBehavior1 перетаскивания false и bottomSheetBehavior2 true


Решение

Поместите этот код, и ваша проблема решена.

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 для вашего репо с полностью работающим изменения.

person N J    schedule 09.05.2017
comment
Так просто хочется плакать. Большое спасибо. - person Tim Malseed; 09.05.2017
comment
Добро пожаловать :). Не за что. Рад помочь вам. - person N J; 09.05.2017
comment
Град идея слушать событие касания. Я добился желаемого поведения с помощью: bottomSheetDialog.setHideable (false); - person bastiotutuama; 15.03.2018