在 Fragments 或 Activity 中使用工具栏的协调器布局

Coordinator Layout with Toolbar in Fragments or Activity

新的设计库中有几个新的布局,如果开发人员愿意,它们可以极大地改变工具栏的行为方式。由于不同的片段具有不同的行为和目标,例如带有显示重要照片的折叠工具栏的画廊片段,或者没有滚动视图的片段,它不需要用于隐藏工具栏的 appbarlayout,在 activity 可以证明是困难的。

因此,我是否应该将工具栏移动到每个片段?如果是这样,我每次显示一个片段时都必须设置 supportActionBar 并且还要在片段中引用 activity ,这使片段的独立性无效。如果我单独保留 Activity 中的工具栏,我必须为每个片段中的每种行为类型定义多个布局。什么是最好的方法?

这是一个非常好的问题:需要像 ActionBar 一样工作的 Toolbar 应该保存在 Activity 还是 Fragment 中?在搜索了不同的问题和文档之后,我找不到涵盖所有情况的解决方案。因此,这实际上取决于您的情况。

情况 1:Toolbar 必须是 ActionBar 替换

如果 Toolbar 的行为必须像普通的 ActionBar(或者如果不时显示最多 1 个片段),我认为 best/simplest 方法是使用传统的 Activities 和自己的工具栏并将您的片段放在那里。这样您就不必担心何时必须显示哪个工具栏。

也可以从 Fragment 更改 ActionBar(-behaviour),但我不推荐这样做,因为这会迫使您跟踪哪个 Fragment 何时更改了 ActionBar。我什至不知道是否可以多次设置ActionBar。

情况 2:每个 Fragment 应该有自己的(部分)工具栏

您还可以选择将不同的独立工具栏放在不同的片段中,并具有它们自己的操作。通过这种方式,您可以并排显示不同的片段 - 每个片段在其工具栏中都有自己的操作 - 并建议它是 1 个工具栏(可能像 Gmail 应用程序,尽管我不确定)。然而,这意味着您必须自己给这些工具栏充气,但这一定不是很困难。

希望对您的选择有所帮助

(抱歉,如果我犯了任何(语言)错误)

对我来说,在每个片段中都有应用栏和工具栏听起来太奇怪了。所以我选择在 activity.

中使用带工具栏的单个应用栏

要使用 CoordinatorLayout 解决该问题,您必须设置 FrameLayout(或任何其他布局)的不同行为,这些行为应该包含您想要覆盖默认行为的每个片段的片段。

假设您的默认行为是 app:layout_behavior="@string/appbar_scrolling_view_behavior"

那么在你的 fragment_activity_layout.xml 中你可能有这样的东西:

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

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/dashboard_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.Toolbar"
            app:layout_scrollFlags="scroll|enterAlways"/>
    </android.support.design.widget.AppBarLayout>

    <FrameLayout
        android:id="@+id/dashboard_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>

并且在您不希望实现的每个片段中 app:layout_behavior="@string/appbar_scrolling_view_behavior" 您将不得不覆盖 onAttachonDetach 方法,这将改变您的 FrameLayout 的行为:

CoordinatorLayout.Behavior behavior;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if(behavior != null)
        return;

    FrameLayout layout =(FrameLayout) getActivity().findViewById(R.id.dashboard_content);
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) layout.getLayoutParams();

    behavior = params.getBehavior();
    params.setBehavior(null);

}

@Override
public void onDetach() {
    super.onDetach();
    if(behavior == null)
        return;

    FrameLayout layout =(FrameLayout) getActivity().findViewById(R.id.dashboard_content);
    CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) layout.getLayoutParams();

    params.setBehavior(behavior);

    layout.setLayoutParams(params);

    behavior = null;
}

之后 CoordinatorLayout 将不会折叠 appbar 等,并允许 fragment 布局为全高。

这是我的解决方案

<!-- Put your fragment inside a Framelayout and set the behavior for this FrameLayout -->
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <!-- Your fragment -->
    <include layout="@layout/content_main" />

</FrameLayout>

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/AppTheme.PopupOverlay" />

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

导航就是这样documentation says:

Adding the top app bar to your activity works well when the app bar’s layout is similar for each destination in your app. If, however, your top app bar changes substantially across destinations, then consider removing the top app bar from your activity and defining it in each destination fragment, instead.

实际上设置一个 Toolbar using NavigationUI 非常容易,而且这个解决方案不需要 Fragment 了解其父级。例如:

<!-- my_fragment.xml -->
<androidx.constraintlayout.widget.ConstraintLayout ...>

  <com.google.android.material.appbar.MaterialToolbar
    android:id="@+id/toolbar"
    ... />

</androidx.constraintlayout.widget.ConstraintLayout>
class MyFragment : Fragment() {
  ...

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    val navController = findNavController()
    binding.toolbar.setupWithNavController(navController)
  }
}

您可以找到完整的 GitHub 示例 here. There's also a relative question that might be interested Is setSupportActionbar required anymore?