Прокрутка не работает с координаторомLayout + изображение параллакса + BottomSheetLayout
Введение
У меня есть активность, которая реализует общий шаблон с изображением заголовка параллакса и прокручиванием содержимого с помощью CoordinatorLayout
, AppBarLayout
и CollapsingToolbarLayout
. Мой XML-макет выглядит следующим образом:
<android.support.design.widget.CoordinatorLayout
android:fitsSystemWindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent">
<android.support.design.widget.AppBarLayout
android:fitsSystemWindows="true"
android:id="@+id/appbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.design.widget.CollapsingToolbarLayout
android:fitsSystemWindows="true"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<TextView
android:background="@color/colorAccent"
android:gravity="center"
android:layout_height="250dp"
android:layout_width="match_parent"
android:text="ParallaxImage"
app:layout_collapseMode="parallax"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/content"
android:layout_height="match_parent"
android:layout_width="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:layout_width="wrap_content"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
Как вы можете видеть в анимации gif ниже, все работает правильно. Вы можете прокручивать весь экран из содержимого NestedScrollView
, а также из Toolbar
или параллакса View
.
![AppBarLayout + NestedScrollView]()
Проблема
Google представил класс BottomSheetBehavior
(поддержка поддержки дизайна Android 23.2), чтобы помочь разработчикам реализовать Нижние листы. Мой xml-макет с нижним листом выглядит следующим образом:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<!-- ommited -->
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!-- ommited -->
</android.support.v4.widget.NestedScrollView>
<LinearLayout
android:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="@android:color/holo_blue_bright"
android:orientation="vertical"
app:behavior_peekHeight="?attr/actionBarSize"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<TextView
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="BottomSheetLayout"
android:textColor="@android:color/white"/>
<android.support.v4.widget.NestedScrollView
android:id="@+id/bottomSheetContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="@android:color/holo_green_dark"
android:padding="16dp"
android:text="@string/large_text"
android:textColor="@android:color/white"/>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
И результат будет выглядеть следующим образом:
![введите описание изображения здесь]()
Как вы можете видеть, теперь я не могу прокручивать, если я начну прокручиваться из параллакса View
. Прокрутка из содержимого NestedScrollView
и из Toolbar
работает, как ожидалось.
Вопрос
Как я могу управлять прокруткой для работы с parallax View
(так же, как и в первой анимации gif)? Кажется, что BottomSheetBehavior
перехватывает события касания и препятствует AppBarLayout
(AppBarLayoutBehavior
) обрабатывать свиток. Но странно, что прокрутка из Toolbar
работает, и оба параллакса View
и Toolbar
являются дочерними элементами AppBarLayout
.
Ответы
Ответ 1
Я думаю, что вы должны использовать NestedScrollView
с BottomSheetBehavior
, заменить удар как bootemSheet!
<android.support.v4.widget.NestedScrollView
android:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="@android:color/holo_blue_bright"
android:orientation="vertical"
app:behavior_peekHeight="?attr/actionBarSize"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="BottomSheetLayout"
android:textColor="@android:color/white"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="@android:color/holo_green_dark"
android:padding="16dp"
android:text="@string/large_text"
android:textColor="@android:color/white"/>
</ScrollView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
NestedScrollView
может знать, как вставить в панель инструментов, а не LinearLayout
!
хочу помочь!
Ответ 2
Похоже на ошибку в коде BottomSheetBehavior
, вероятно, потому что если вы попытаетесь отладить код CoordinatorLayout
, вы увидите, что при касании вашего параллакса View
он будет определен как макет с BottomSheetBehavior
вместо HeaderBehavior
.
Итак, быстрые исправления, которые я нашел, это установить OnTouchListener
, который всегда возвращает true в представлении parallax:
View parallaxView = findViewById(R.id.parallax_view);
parallaxView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
Конечно, не забудьте установить android:id="@+id/parallax_view"
на ваш просмотр с помощью режима сглаживания параллакса.
Надеюсь, что это поможет!
Ответ 3
попробуйте это
<LinearLayout
android:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="400dp">
изменить высоту 400dp на wrap_content
надежда работает для вас
Ответ 4
Я копирую вставляемый XML-код, который я использую. Он работает на Samsung Galaxy S3, Huawei Mate 8 и Moto, кстати, и я еще не пробовал эмулятор (я удалил все деловые вещи и просто добавил фиктивные виджеты).
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinatorlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="256dp"
android:theme="@style/AppTheme.AppBarOverlay"
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/AppTheme.PopupOverlay"
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:paddingBottom="16dp">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp">
<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="Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo." />
</LinearLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp">
<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="TITLE"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 2" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 3" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 4" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 5" />
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:behavior_peekHeight="100dp"
android:fitsSystemWindows="true"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="16dp"
android:background="@android:color/white"
android:padding="15dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="BOOTOMSHEET TITLE"
android:textAppearance="@style/TextAppearance.AppCompat.Title" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 2"
android:layout_margin="10dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 3"
android:layout_margin="10dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="text 4"
android:layout_margin="10dp"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="320dp"
android:background="@color/colorAccent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Your remaining content here"
android:textColor="@android:color/white" />
</FrameLayout>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
Ответ 5
Проблема может быть решена путем перемещения NestedScrollView (или фрагмента, содержащего NestedScrollView в моем случае) вне координатораLayout в FrameLayout и размещения фиктивного представления, где NestedScrollView был таким:
<FrameLayout>
<CoordinatorLayout>
<AppBarLayout>
...
</AppBarLayout>
<View
android:id="@+id/bottomSheet"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior" />
</CoordinatorLayout>
<NestedScrollView
android:id="@+id/bottomSheetContent">
...
</NestedScrollView>
</FrameLayout>
Наконец, добавьте BottomSheetCallback
в фиктивный вид, который преобразует фактический просмотр содержимого во время скольжения:
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
bottomSheetContent.setTranslationY((1f - slideOffset) * bottomSheetContent.getHeight());
}
По-видимому, это единственный способ помешать координатору Layout реагировать на (и перехватывать) любые события касания. #JustGoogleThings
Ответ 6
Я придумал свой собственный ответ:
-
добавьте app:layout_behavior="...AppBarLayoutCustomBehavior"
к вашему appBarLayout
.
-
создайте этот класс и простирайтесь от AppBarLayout.Behavior
-
переопределить onStartNestedScroll
и onNestedFling
-
создайте флаг типа scrollDenial
и добавьте его в оба метода ниже, затем вызовите super (scrollDenial && super.onStartNestedScroll...)
-
теперь вам нужно обновить свое условие отказа на каждом onStartNestedScroll. Я сделал что-то вроде этого:
https://gist.github.com/recoverrelax/8dd37b54910d70b5cd6a130a070c51e9
Ps. Извините, но это Котлин: Это не должно быть трудно понять. Он решил проблему bottomSheet.