Как reset позиция панели инструментов, управляемая координаторомLayout?

Приложение, над которым я работаю, состоит из ящика навигации, который реализован в Activity. Макет действия выглядит следующим образом:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<android.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinator"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <include
            android:id="@+id/appbar"
            layout="@layout/appbar" />

    </android.support.design.widget.CoordinatorLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/header_drawer"
        app:menu="@menu/menu_nav">
    </android.support.design.widget.NavigationView>

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

</FrameLayout>

Это очень распространенный шаблон, только часто изменяющееся значение - это фрагмент внутри макета контейнера.

Если какой-либо из фрагментов имеет прокручиваемый элемент, при прокрутке координаторLayout с радостью сделает переводы положения, включая панель инструментов /AppBarLayout.

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

Результат:

Это:

After scroll

Задерживается:

Then change

Как можно reset позиция панели инструментов для этого случая?

EDIT: Вероятно, ошибка, прослушиватель изменений смещения AppBarLayout вызывается только при повторном запуске приложения (нажмите кнопку "Назад" и откройте приложение) и перестанет получать вызов снова после интенсивного перехода.

Ответ 1

В reset состояние прокрутки, просто получите объект AppBarLayout.Behavior

CoordinatorLayout coordinator = (CoordinatorLayout) findViewById(R.id.coordinator);
AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();       

и вызовите метод onNestedPreScroll вручную:

int[] consumed = new int[2];
behavior.onNestedPreScroll(coordinator, appbar, null, 0, -1000, consumed);

Если вы хотите reset плавно с анимацией, вы можете попробовать вместо onNestedFling:

behavior.onNestedFling(coordinator, appbar, null, 0, -1000, true);

Ответ 2

Сначала получите подтверждение AppBarLayout в вашем MainActivity, затем в состоянии паузы заменяемого фрагмента используйте следующий метод, чтобы развернуть панель инструментов:

MainActivity.appbar.setExpanded(true,true);

И или закрыть панель инструментов:

MainActivity.appbar.setExpanded(false,true);

Второй параметр используется для прокрутки панели инструментов плавно.

Ответ 3

Обновите свою поддержку lib до v23, затем вы можете использовать:

appBarLayout.setExpanded(true/false);

public void setExpanded (boolean расширенный)

Устанавливает, расширяется ли этот AppBarLayout или нет, оживляя, если он уже был выложен.

Как и при прокрутке AppBarLayout, этот метод полагается на этот макет, являющийся прямым дочерним элементом CoordinatorLayout.

расширенный true, если макет должен быть полностью расширен, false, если он должен быть полностью скомпенсирован

Ответ 4

@razzledazzle В AppBarLayout хранятся onOffsetChangedListeners как WeakReferences, что означает, что они собирают мусор, когда это необходимо, например, когда вы делаете интенсивный бросок. См. Решение здесь:

https://code.google.com/p/android/issues/detail?id=176328

Ответ 5

Я использую эти коды до изменения фрагмента.

scrollingElement.startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
scrollingElement.dispatchNestedPreScroll(0, -Integer.MAX_VALUE, null, null);
scrollingElement.stopNestedScroll();

Ответ 6

Замените FrameLayout android.support.design.widget.CoordinatorLayout на android.support.design.widget.CoordinatorLayout с помощью android.support.v4.widget.NestedScrollView, и он автоматически выполнит задание без каких-либо других хаков.... так что это будет выглядеть так:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <include
        android:id="@+id/appbar"
        layout="@layout/appbar" />

</android.support.design.widget.CoordinatorLayout>

Ответ 7

Как сказано в документе said

AppBarLayout поддерживает
void setExpanded (логическое расширение, логическое анимация);
Устанавливает, будет ли этот AppBarLayout расширен или нет.

  • расширенный логический: true, если макет должен быть полностью развернут, и false, если он должен быть полностью свернут
  • animate boolean: нужно ли анимировать в новое состояние

Итак, сначала вам нужно

AppBarLayout appBarLayout = findViewById(R.id.appBarLayout);

затем разверните макет

appBarLayout.setExpanded(true, true); // with animation
appBarLayout.setExpanded(true, false); // without animation  

и свернуть макет

appBarLayout.setExpanded(false, true); // with animation
appBarLayout.setExpanded(false, false); // without animation