如何重置由 CoordinatorLayout 控制的 Toolbar 位置?

How to reset the Toolbar position controlled by the CoordinatorLayout?

我正在开发的应用程序包含一个在 Activity 中实现的导航抽屉。 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>

这是一个很常见的模式,唯一经常变化的是容器布局里面的Fragment。

如果任何片段有滚动元素,在滚动时,CoordinatorLayout 会愉快地进行位置转换,包括 Toolbar/AppBarLayout.

这里真正的问题是,当 Fragment 被替换时,Toolbar 的位置保持不变,即,如果 Toolbar 被隐藏,它将保持原样 这不是故意的。

结果是这样的:

这个:

卡住:

对于这种情况,如何重置工具栏位置?

编辑: 可能是一个错误,AppBarLayout 偏移量更改侦听器仅在重新启动应用程序(按返回按​​钮并打开应用程序)时被调用,并且在激烈的投掷后不再被调用。

我在片段更改之前使用此代码。

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

要重置滚动状态,只需获取 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);

如果你想用动画顺利重置,你可以尝试调用onNestedFling

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

@razzledazzle AppBarLayout 将 onOffsetChangedListeners 存储为 WeakReferences,这意味着它们会在需要时被垃圾回收,例如当您进行激烈的投掷时。在此处查看解决方案:

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

首先在你的MainActivity中获取一个AppBarLayout引用,然后在被替换的fragment暂停状态下,使用下面的方法展开toolbar :

MainActivity.appbar.setExpanded(true,true);

然后或关闭工具栏:

MainActivity.appbar.setExpanded(false,true);

第二个参数用于平滑滚动工具栏

将您的支持库更新到 v23 然后您可以使用:

appBarLayout.setExpanded(true/false);

public void setExpanded (boolean expanded)

Sets whether this AppBarLayout is expanded or not, animating if it has already been laid out.

As with AppBarLayout's scrolling, this method relies on this layout being a direct child of a CoordinatorLayout.

expanded true if the layout should be fully expanded, false if it should be fully collapsed

android.support.v4.widget.NestedScrollView 替换或包裹 android.support.design.widget.CoordinatorLayout 内的 FrameLayout,这将自动完成工作,无需任何其他hacks....所以它看起来像这样:

<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>

正如document所说

AppBarLayout supports
void setExpanded (boolean expanded, boolean animate);
Sets whether this AppBarLayout is expanded or not.

  • expanded boolean: true if the layout should be fully expanded, false if it should be fully collapsed
  • animate boolean: Whether to animate to the new state

所以首先,你需要

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 
// Get the reference for appbar from layout
AppBarLayout appbar = rootView.findViewById(R.id.appbar);
//boolean expanded, boolean animate
appbar.setExpanded(true, true);

我遇到了类似的问题。当我动态调整布局大小时,我的布局要么高于需要(如此处),要么低于需要。它是以编程方式在 FrameLayout 中替换的 Fragment。 我做了什么:我开始重新创建我的片段以更改 FrameLayout 大小。

myFragment = new MyFragment();
getSupportFragmentManager().beginTransaction()
                .replace(R.id.frame_layout, myFragment)
                .commit();