Использование метода BottomSheetBehavior с внутренним координаторомLayout

В библиотеке поддержки дизайна BottomSheetBehavior представлен BottomSheetBehavior , который позволяет дочерним элементам координатора действовать как нижние листы (просмотры перетаскиваются из нижней части экрана).

То, что я хотел бы сделать, – иметь в качестве представления нижнего листа следующий вид (типичный координатор + сворачивающийся материал):

 <CoordinatorLayout app:layout_behavior=“@string/bottom_sheet_behavior”> <AppBarLayout> <CollapsingToolbarLayout> <ImageView /> </CollapsingToolbarLayout> </AppBarLayout> <NestedScrollView> <LinearLayout> < Content ... /> </LinearLayout> </NestedScrollView> </CoordinatorLayout> 

К сожалению, представления нижнего листа должны реализовывать вложенную прокрутку, иначе они не будут получать события прокрутки. Если вы попытаетесь выполнить основную операцию и затем загрузите это представление в качестве нижнего листа, вы увидите, что события прокрутки действуют только на «листе» бумаги с некоторым странным поведением, так как вы можете видеть, продолжаете ли вы читать.

Я уверен, что это может быть обработано путем подклассификации CoordinatorLayout или даже лучше с помощью подкласса BottomSheetBehavior . У вас есть намек?

Некоторые мысли

  • requestDisallowInterceptTouchEvent() следует использовать, чтобы украсть события у родителя в некоторых условиях:

    • Когда смещение AppBarLayout > 0
    • Когда смещение AppBarLayout равно == 0, но мы прокручиваем (подумаем об этом на секунду, и вы увидите)
  • Первое условие можно получить, установив OnOffsetChanged во внутреннюю панель приложения;

  • Для второго требуется некоторая обработка событий, например:

     switch (MotionEventCompat.getActionMasked(event)) { case MotionEvent.ACTION_DOWN: startY = event.getY(); lastY = startY; userIsScrollingUp = false; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: userIsScrollingUp = false; break; case MotionEvent.ACTION_MOVE: lastY = event.getY(); float yDeltaTotal = startY - lastY; if (yDeltaTotal > touchSlop) { // Moving the finger up. userIsScrollingUp = true; } break; } 

вопросы

Излишне говорить, что я не могу сделать эту работу прямо сейчас. Я не могу поймать события, когда условия соблюдены, и не поймать их в других случаях. На изображении ниже вы можете видеть, что происходит со стандартным CoordinatorLayout:

  • Лист отклоняется, если вы прокрутите вниз панель приложений, но не прокрутите вниз по вложенному контенту. Кажется, что вложенные события прокрутки не распространяются на поведение Координатора;

  • Существует также проблема с внутренней панелью приложения: вложенное содержимое прокрутки не следует за панелью приложения, когда она рушится.

Введите описание изображения здесь

Я установил образец проекта на github, который показывает эти проблемы.

Чтобы быть ясным, желаемое поведение:

  • Правильное поведение виджетов / прокрутки внутри листа;

  • Когда лист расширяется, он может свернуть при прокрутке вниз, но только если внутренняя панель приложения полностью расширена . Сейчас он рухнет, не касаясь состояния панели приложений, и только если вы перетащите панель приложения;

  • Когда лист рушится, прокручивание жестов расширит его (без влияния на внутреннюю панель приложения).

Пример из приложения контактов (который, вероятно, не использует метод BottomSheetBehavior, но это то, что я хочу):

Введите описание изображения здесь

Solutions Collecting From Web of "Использование метода BottomSheetBehavior с внутренним координаторомLayout"

Я просто следил за тем, как вы задали вышеуказанный вопрос, и придумал решение, которое может потребовать больше объяснений. Пожалуйста, следуйте своему образцу кода и интегрируйте дополнительную часть в свой xml, чтобы заставить ее вести себя как поведение BottomSheeet

 <CoordinatorLayout> <AppBarLayout> <Toolbar app:layout_collapseMode="pin"> </Toolbar> </AppBarLayout> <NestedScrollView app:layout_behavior=“@string/bottom_sheet_behavior” > <include layout="@layout/items" /> </NestedScrollView> <!-- Bottom Sheet --> <BottomSheetCoordinatorLayout> <AppBarLayout <CollapsingToolbarLayout"> <ImageView /> <Toolbar /> </CollapsingToolbarLayout> </AppBarLayout> <NestedScrollView"> <include layout="@layout/items" /> </NestedScrollView> </BottomSheetCoordinatorLayout> </CoordinatorLayout> 

Примечание. Решение, которое сработало для меня, уже объяснено в последнем комментарии к вашему вопросу

Лучшее объяснение: https://github.com/laenger/BottomSheetCoordinatorLayout

Я, наконец, выпустил свою реализацию. Найдите его на Github или прямо из jcenter:

 compile 'com.otaliastudios:bottomsheetcoordinatorlayout:1.0.0' 

Все, что вам нужно сделать, это использовать BottomSheetCoordinatorLayout в качестве корневого представления для вашего нижнего листа. Он автоматически раздует рабочее поведение для себя, поэтому не беспокойтесь об этом.

Я использую это в течение длительного времени и не должен иметь проблем с прокруткой, поддерживает перетаскивание на ABL и т. Д.

Если первый ребенок является nestedscroll это вызовет некоторые другие проблемы. Это решение исправлено моей проблемой, я надеюсь, также исправить вашу.

 <CoordinatorLayout app:layout_behavior=“@string/bottom_sheet_behavior”> <AppBarLayout> <CollapsingToolbarLayout> <ImageView /> </CollapsingToolbarLayout> </AppBarLayout> </LinearLayout> <NestedScrollView> <LinearLayout> < Content ... /> </LinearLayout> </NestedScrollView> </LinearLayout> </CoordinatorLayout> 

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

Попробуйте следующее:

 <CoordinatorLayout app:layout_behavior=“@string/bottom_sheet_behavior”> <AppBarLayout> <CollapsingToolbarLayout> <ImageView /> </CollapsingToolbarLayout> </AppBarLayout> <LinearLayout> <!--don't forget to addd this line--> app:layout_behavior="@string/appbar_scrolling_view_behavior"> < Content ... /> </LinearLayout> 

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

Это решение его проблемы: ❌ панель инструментов иногда рушится слишком рано

Для предотвращения этого вам необходимо создать свой пользовательский AppBarLayout.Behavior , так как это когда вы прокручиваете вверх, все еще перетаскивая, что AppBarLayout.behavior получает движение прокрутки. Нам нужно определить, находится ли оно в STATE_DRAGGING и просто вернуться, чтобы преждевременно скрывать / сворачивать панель инструментов.

 public class CustomAppBarLayoutBehavior extends AppBarLayout.Behavior { private CoordinatorLayoutBottomSheetBehavior behavior; public CustomAppBarLayoutBehavior() { } public CustomAppBarLayoutBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) { behavior = CoordinatorLayoutBottomSheetBehavior.from(parent); return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes); } @Override public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) { if(behavior.getState() == CoordinatorLayoutBottomSheetBehavior.STATE_DRAGGING){ return; }else { super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); } } @Override public void setDragCallback(@Nullable DragCallback callback) { super.setDragCallback(callback); } } 

Это может быть хорошим началом того, как мы решаем другие вопросы:

❌ панель инструментов не может быть свернута за счет перетаскивания

❌ компоновка главного координатора потребляет некоторую прокрутку

Я на самом деле не хороший пользовательский интерфейс / анимация, но трудолюбие оплачивает иногда понимание кода, нахождение правильной функции обратного вызова / переопределения для реализации.

Задайте это как поведение для appbarlayout

 <android.support.design.widget.AppBarLayout android:id="@+id/bottom_sheet_appbar" style="@style/BottomSheetAppBarStyle" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="your.package.CustomAppBarLayoutBehavior"> 

Макет для полного экрана макета панели приложений выглядит следующим образом:

 <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="@dimen/detail_backdrop_height" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:fitsSystemWindows="true"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll|exitUntilCollapsed" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:expandedTitleMarginStart="48dp" app:expandedTitleMarginEnd="64dp"> <ImageView android:id="@+id/backdrop" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="24dp"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Info" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/card_margin" android:layout_marginLeft="@dimen/card_margin" android:layout_marginRight="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Friends" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/card_margin" android:layout_marginLeft="@dimen/card_margin" android:layout_marginRight="@dimen/card_margin"> <LinearLayout style="@style/Widget.CardContent" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Related" android:textAppearance="@style/TextAppearance.AppCompat.Title" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/cheese_ipsum" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_height="wrap_content" android:layout_width="wrap_content" app:layout_anchor="@id/appbar" app:layout_anchorGravity="bottom|right|end" android:src="@drawable/ic_discuss" android:layout_margin="@dimen/fab_margin" android:clickable="true"/> 

И после этого вы должны реализовать AppBarLayout.OnOffsetChangedListener в своем классе и установить смещение экрана.