Подтвердить что ты не робот

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

В библиотеке поддержки дизайна 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 равно == 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;
    }
    

Вопросы

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

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

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

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

compile 'com.otaliastudios:bottomsheetcoordinatorlayout:1.0.0’

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

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

Ответ 2

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

Ответ 3

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

<CoordinatorLayout
    app:layout_behavior="@string/bottom_sheet_behavior">

   <AppBarLayout>
        <CollapsingToolbarLayout>
           <ImageView />
        </CollapsingToolbarLayout>
    </AppBarLayout>
</LinearLayout>
    <NestedScrollView>
        <LinearLayout>
            < Content ... />
        </LinearLayout>
    </NestedScrollView>
</LinearLayout>
</CoordinatorLayout>

Ответ 4

Попытайтесь не использовать 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>

Ответ 5

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

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

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

Ответ 6

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

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