RecyclerView (горизонтальный), вложенный в BottomSheet, предотвращающий вертикальную прокрутку

У меня есть RecyclerView, использующий LinearLayoutManager с ориентацией HORIZONTAL, вложенный в FrameLayout с использованием BottomSheet Behavior.

При попытке вертикального перетаскивания через RecyclerView BottomSheet не реагирует на событие перетаскивания. Предположительно, это связано с тем, что вертикальная прокрутка отключена для LayoutManager с горизонтальной ориентацией.

Я пытался переопределить LinearLayoutManager.canScrollVertically() и вернуть true. Это вроде работает. Если очень осторожно перетащить вертикально, BottomSheet отреагирует. Однако, как только происходит какое-либо горизонтальное движение, BottomSheet перестает реагировать на события вертикального перетаскивания.

Я не уверен, что переопределение canScrollVertically() является правильным подходом здесь — это определенно не кажется правильным с точки зрения UX.

Я также заметил, что если я использую ViewPager, а не RecyclerView с горизонтально ориентированным LayoutManager, BottomSheet реагирует на события вертикального смахивания по желанию.

Есть ли какой-то другой метод LayoutManager, RecyclerView, BottomSheet Behavior или что-то еще, что может помочь распространить события вертикальной прокрутки на BottomSheet Behavior?

Вот пример проблемы:

https://github.com/timusus/bottomsheet-test (проблема может быть воспроизведена с коммитом # ф59а7031)

Просто разверните первый нижний лист.


person Tim Malseed    schedule 09.05.2017    source источник


Ответы (1)


Где проблема? В 1_. BottomSheet отлично работает, если положить его внутрь CoordinatorLayout. Затем BottomSheet может передать свое состояние прокрутки через CoordinatorLayout другим представлениям, которые являются прямыми дочерними элементами CoordinatorLayout.

Почему RecyclerView не смог передать состояние прокрутки BottomSheet? Это не прямой потомок CoordinatorLayout. Но есть способ их передать: RecyclerView должен быть в поле зрения, который реализует NestedScrollingParent и NestedScrollingChild. Ответ на это: NestedScrollView

Таким образом, ваши макеты fragment_sheetX.xml должны выглядеть так:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff"
    android:orientation="vertical"
    android:fillViewport="true">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</android.support.v4.widget.NestedScrollView>

Обратите также внимание на android:fillViewport="true", иначе ваш RecyclerView не займет всю высоту.

Однако это все равно не сработает. Почему? RecyclerView нужно передать родительскому элементу вертикальную прокрутку. Как? Ответ recyclerView.setNestedScrollingEnabled(false);, но это лучше описано здесь.

Кстати: MultiSheetView — отличная функция и очень интересный подход к мобильному UX-дизайну.

person R. Zagórski    schedule 25.06.2017
comment
Я подозревал, что FrameLayout препятствует распространению событий прокрутки на CoordinatorLayout. Я думаю, что в какой-то момент я приблизился к этому решению, но у меня возникли проблемы с проблемой окна просмотра. Большое спасибо. - person Tim Malseed; 26.06.2017
comment
если иерархия: NestedScrollView -> ConstraintLayout -> RecylerView, прокрутка RecyclerView ведет себя неправильно... Я могу прокручивать вниз, но не вверх. При попытке прокрутки вверх нижний лист (в данном случае NestedScrollView) рушится... есть идеи? - person skm; 06.01.2019
comment
Этот метод приводит к тому, что RecyclerView имеет высоту, эквивалентную wrap_content, что ужасно для производительности, поскольку приводит к тому, что ViewHolders для всех дочерних элементов раздуваются индивидуально без повторного использования. - person Josh; 18.01.2019
comment
Большое спасибо, этот ответ решил мою проблему. - person Fereshteh Naji; 17.04.2021