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

библиотека поддержки дизайна v. 23.2 ввел 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 offset is == 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:

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

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

enter image description here

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

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

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

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

  • когда лист свернут, прокрутите вверх жесты расширят его (без эффекта на внутренней панели приложений).

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

enter image description here

6 ответов


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

compile 'com.otaliastudios:bottomsheetcoordinatorlayout:1.0.0’

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

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


Я просто следил за тем, как вы задали вышеуказанный вопрос, и придумал решение, которое может потребовать больше объяснений.Пожалуйста, следуйте вашему образцу кода и интегрировать дополнительную часть в 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>

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

лучше explantion : https://github.com/laenger/BottomSheetCoordinatorLayout


Если первый ребенок 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>


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

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

чтобы предотвратить это, вам нужно создать свой пользовательский 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);
    }
}

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

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

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

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

как поведение 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">

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

<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 в вашем классе и установить смещение экрана.