【问题标题】:Coordinator Layout with Toolbar in Fragments or Activity片段或活动中带有工具栏的协调器布局
【发布时间】:2015-06-09 18:18:05
【问题描述】:

有了新的设计库,有几个新的布局可以改变工具栏的行为方式,如果开发人员愿意的话。由于不同的 Fragment 有不同的行为和目标,例如具有可折叠工具栏的画廊 Fragment 显示重要照片,或者没有滚动视图的 Fragment 不需要 appbarlayout 来隐藏工具栏,因此在活动中具有单个工具栏可以证明是困难的。

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

【问题讨论】:

  • 您好,您找到解决方案了吗?
  • 对于我当前的项目,我决定坚持使用 Activity 中的工具栏,并在需要时执行适当的动画。但这有点令人费解。我尝试在每个片段中使用工具栏,效果很好,但是在片段转换之间为工具栏设置动画更加困难,我什至不知道是否可行,因为我对片段转换动画没有太多经验。
  • 现在有任何更新或更好的解决方案吗?

标签: android android-fragments android-activity android-actionbar


【解决方案1】:

对我来说,在每个片段中都有 appbar 和工具栏听起来太奇怪了。所以我选择在活动中使用带有工具栏的单个 appbar。

要使用 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 等,并将允许片段布局为全高。

【讨论】:

  • 不错,必须尝试一下,看看它是否简化了事情。谢谢。
  • 如果您能找到更简单的方法,请告诉我。我认为在片段的生命周期中的任何时候都可以更改协调器的行为(例如,您通常有一个带有一些东西的回收器,但在极少数情况下它可能是空的,您会知道只有在 Loader 的onLoadFinished 之后,才有可能你想显示居中的图像,通知这里什么都没有,就像在收件箱应用程序中一样),但我还没有尝试过。也许今天晚些时候。
  • 好的,效果很好。我创建了一个助手,它负责在适当的时候启用/禁用协调器,所以我只是从片段中调用 enableCoordinator(Activity activity) / disableCoordinator(Activity activity)
  • 你的助手在哪里,@КлаусШварц?你什么时候调用它?
  • @santhyago 在片段中
【解决方案2】:

这是我的解决方案

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

【讨论】:

    【解决方案3】:

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

    案例1:Toolbar必须是ActionBar替换

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

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

    案例 2:每个 Fragment 都应该有自己的(部分)工具栏

    您还可以选择将不同的独立工具栏放在不同的片段中,并使用它们自己的操作。这样,您可以在彼此旁边显示不同的片段 - 每个片段在其工具栏中都有自己的操作 - 并建议它是 1 个工具栏(可能像 Gmail 应用程序,虽然我不确定)。然而,这意味着您必须自己为这些工具栏充气,但一定不会很困难。

    我希望这将有助于做出选择。

    (对不起,如果我犯了任何(语言)错误)

    【讨论】:

    • 很抱歉,但这并不能真正解决与新设计库相关的问题。当然,将工具栏作为操作栏是目标,但是为不同类型的工具栏设置多个协调器布局可能会很棘手。我发现可以根据需要为工具栏设置动画。我仍然需要更好地测试它,但似乎有很好的结果
    【解决方案4】:

    这就是导航documentation says:

    当应用栏的布局对于您应用中的每个目的地都相似时,将顶部应用栏添加到您的 Activity 效果很好。但是,如果您的顶部应用栏在各个目的地之间发生显着变化,请考虑从您的活动中移除顶部应用栏并在每个目的地片段中定义它。

    实际上,使用NavigationUI 设置Toolbar 非常容易,并且此解决方案不需要 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。还有一个可能感兴趣的相关问题Is setSupportActionbar required anymore?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-21
      • 1970-01-01
      • 2020-12-11
      • 2016-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多