如何使用 Jetpack 导航组件修复 CollapsingToolbarLayout 不与 RecyclerView 折叠? (导航界面)

How to fix CollapsingToolbarLayout not collapsing with RecyclerView using the Jetpack Navigation Component? (NavigationUI)

我正在使用新的 Jetpack 导航组件和 NavigationUI class 设置应用程序导航,以支持在 CollapsingToolbarLayout 中导航。 但是,使用 documentation.

中的 code/method 不起作用

我已经按照文档中所示设置了 MainActivity: LinearLayout 作为父视图,在 AppBarLayout 中,在 CollapsingToolbarLayout 中,以及工具栏本身。和主机片段。

导航开始目的地是一个FrameLayout,其中包含实际的RecyclerView。

我尝试了各种 layout_scrollFlags 并尝试将 CoordinatorLayout 设置为父视图而不是 LinearLayout。

activity_main.xml

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

    <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleGravity="top"
                app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <androidx.appcompat.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:background="?attr/colorPrimary"
                    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:layout_collapseMode="pin"/>
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <fragment
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph"/>
</LinearLayout>

在MainActivity的onCreate函数中:

// Set Toolbar as ActionBar
setSupportActionBar(findViewById(R.id.toolbar))

val layout = findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar_layout)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(navController.graph)
layout.setupWithNavController(toolbar, navController, appBarConfiguration)

我预计崩溃行为的第一个目的地:

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

    <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/restaurant_recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:listitem="@layout/restaurant_item"/>

</FrameLayout>

我预计在滚动 RecyclerView 时工具栏会折叠。 实际上它只是静态的。

我认为 RecyclerView 和 CollapsingToolbar 之间可能缺少联系? 我错过了什么?

找到解决方案。

使用 CoordinatorLayout 作为父视图而不是 LinearLayout。 删除 CollapsingToolbarLayout。 在工具栏中声明layout_scrollFlags(例如app:layout_scrollFlags="scroll|enterAlways|snap")。 并在片段视图中添加 app:layout_behavior="@string/appbar_scrolling_view_behavior"(这很重要,因为我们在主片段中使用了 RecyclerView)

main_activity.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical">

<com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways|snap"
    />

</com.google.android.material.appbar.AppBarLayout>

<fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

MainActivity onCreate

    // Set Toolbar as ActionBar
    setSupportActionBar(findViewById(R.id.toolbar))

    val navController = findNavController(R.id.nav_host_fragment)
    val appBarConfiguration = AppBarConfiguration(navController.graph)
    findViewById<Toolbar>(R.id.toolbar)
        .setupWithNavController(navController, appBarConfiguration)

谢谢你,你是我的救星。我最近也为此苦苦挣扎,所以我更多地尝试了您的解决方案,并且我来了一些 结论(撰写时间 2019-08-08):

TL;DR CollapsingToolbarLayout 也有效,但片段大小不正确。

  1. 顶层布局必须是 CoordinatorLayout,因为如果不是,则无法协调 AppBarLayout 和片段。
  2. <fragment> 元素 必须 具有属性 app:layout_behavior="@string/appbar_scrolling_view_behavior"。似乎 CoordinatorLayout 只在其直接子项中搜索以查找行为。
  3. 拥有AppBarLayout/CollapsingToolbarLayout/Toolbar层级实际上很好。只要 <fragment> 具有 app:layout_behavior 属性,这将 也很好用。
  4. 片段内的布局并不重要。在我的例子中使用视图模型,这意味着我需要一个额外的 <layout> 包装器,所以我已经尝试了两个

    <layout>
      <data></data>
      <FrameLayout>
        <RecyclerView/>
      <FrameLayout>
    </layout>
    

    <layout>
      <data></data>
      <CoordinatorLayout>
        <RecyclerView/>
      <CoordinatorLayout>
    </layout>
    

    两者都可以正常工作。内部 CoordinatorLayout 不会吞下行为,因为 RecyclerView 没有或不使用行为,但这引出了我的下一点:

  5. 这种安排没有正确调整片段的大小。如果您还向片段添加了一个 FloatingActionButton,则它不能与 FrameLayout 一起正常工作(尽管 app:layout_anchorGravity="bottom|right|end" 仍位于左上角的 FAB)。

    如果您在片段内使用 CoordinatorLayout,就像我在上面的第二个示例中那样,FAB 会跳转到正确的位置。显示和隐藏不起作用,即使您自己实现了 ScrollAwareFABBehavior。相反,FAB 滚动到屏幕外,显示片段是视口垂直高度的 100%,但向下移动了工具栏的高度(如果它是展开的 CollapsingToolbarLayout,这可能是 300dp 或几乎是屏幕的一半在我的例子中)。

我一直没能找到解决这个问题的办法,我打算暂时停止尝试。 single-activity/single-toolbar 模型似乎还不能处理 CoordinatorLayout 的事情。 Android 文档使用 LinearLayout 的原因可能是为了确保片段具有正确的垂直尺寸,但同时放弃任何动态行为特征。以后我可能会使用嵌套导航图,应用程序的每个部分都将包含相应的工具栏。

如果有人有任何建议或指点,请发表评论。我希望有一天能真正让这个工作。