片段和导航抽屉有不同的工具栏

12

请帮我解释一下... 我的 Activity 中有一个导航抽屉,并且它与 Toolbar (像 ActionBar) 同步。该 Activity 有几个片段,在不同的片段中,我需要使用不同的 AppBar 模式(在一个片段中是视差,另一个片段中是简单的)。所以,我认为我应该在每个具有 AppBar 和内容的片段中设置 CoordinatorLayout
但是我如何替换最后一个工具栏以保存与抽屉的同步?或者这种方法是错误的,我需要采用其他方法吗?

5个回答

10

我不确定我的方法是否好用,但我尝试添加了这个公共方法到我的活动中:

public void setToolbar(Toolbar toolbar) {
    if(toolbar != null) {
        setSupportActionBar(toolbar);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();
    } else {
        drawer.setDrawerListener(null);
    }
}

我在所有片段中添加了以下内容:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    ((MainActivity)getActivity()).setToolbar(toolbar);
}

@Override
public void onDestroyView() {
    ((MainActivity)getActivity()).setToolbar(null);
    super.onDestroyView();
}

它运行良好,但我不确定它是否会导致内存泄漏或任何其他性能问题。也许有人可以帮忙解决吗?


我解决了这个问题。我只是在活动布局中使用了 DrawerLayout,并在片段布局中使用了 Toolbar,在 onCreateView 中将 Toolbar 设置为 ActionBar 并将其与 DrawerLayout 同步。 - Denis Sologub
而且您的解决方案没有任何内存泄漏) - Denis Sologub
1
@Шах,你能否详细说明一下在fragment的onCreateView中如何与DrawerLayout同步? 你是否为每个fragment的Toolbar重新创建ActionBarDrawerToggle? 你是否使用带有或不带有ToolbarDrawerLayout构造函数? - jayeffkay
@Шах,好的,请回答一下,你是如何使用不同的工具栏创建应用程序的?因为我的应用程序看起来很糟糕。 - CoolMind
@CoolMind,在onCreateView中定义你的Toolbar,然后将其设置为ActionBar并与DrawerLayout同步,就像在普通活动中一样。对于英文版本,我已经不记得如何在onCreateView中定义Toolbar以便它可以像使用DrawerLayout一样使用ActionBar了。 - Denis Sologub
@Шах,谢谢你,好心人!我尝试过这样做,但是遇到了同样的问题(工具栏作为视差和常规操作栏)。因此,我有一个带有DrawerLayout、FrameLayout和NavigationView的活动,所有其他布局都在片段中。但是当我替换片段或想要实现视差效果时,它不能很好地工作。 - CoolMind

5
您可以像以下代码一样从每个Fragment访问主要的DrawerLayout:
AppCompatActivity actionBar = (AppCompatActivity) getActivity();
actionBar.setSupportActionBar(toolbar);

DrawerLayout drawer = (DrawerLayout) actionBar.findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            getActivity(), drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();

你能描述一下Activity和Fragments吗?所有的Fragments都有自己的工具栏还是使用Activity的工具栏?我有一个带有DrawerLayout和NavigationView的Activity,在其中放置了Fragments,它们包含CoordinatorLayout、AppBarLayout和Toolbar,但是它的表现不佳,当切换Fragments时,工具栏的外观并不如我所愿。 - CoolMind

1
如果您想在不同的片段中使用导航抽屉中指定的应用栏(toolbar),例如具有不同选项菜单项的片段,您可以在指定了导航抽屉逻辑的主活动中制作一个公共方法。
public void setToolbar(Toolbar toolbar, String title){
    AppCompatActivity actionBar = this;
    actionBar.setSupportActionBar(toolbar);

    DrawerLayout drawer = (DrawerLayout)actionBar.findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toogle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close);
    drawer.addDrawerListener(toogle);
    toogle.setDrawerIndicatorEnabled(true);
    toogle.syncState();
    if(toolbar != null)
        toolbar.setTitle(title);
}

现在,您可以在片段中使用此方法来访问主工具栏并使用自定义标题、选项菜单进行覆盖... 您可以通过在片段中创建一个新的工具栏变量,然后像这样在onCreateView()方法中填充它来实现。
toolbarFragment = (Toolbar)getActivity().findViewById(R.id.toolbar);

R.id.toolbar 是您在布局文件中指定的工具栏的ID,它是您在主活动中用于主工具栏的相同ID。


现在,您可以在片段中调用以下方法setToolbar(Toolbar toolbar, String title),例如:

((MainActivity)getActivity()).setToolbar(toolbarFragment, "Some title");

如果您想为此片段使用选项菜单,则需要调用以下内容:
setHasOptionsMenu(true);

在片段的onCreate()onCreateView()方法中,然后您可以像这样重写onCreateOptionsMenu()方法。
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    inflater.inflate(R.menu.custom_menu1, menu);
}

你也可以为导航抽屉中的其他片段重复此过程。虽然对我有效,但我不知道这是否违反了活动或片段的生命周期或导致内存泄漏。

不,伙计,这不是问题。我需要为不同的片段制作一个非常灵活和复杂的GUI。它需要完全访问应用程序栏。 - Denis Sologub
我刚刚使用了带视差标题、导航路径(类似于某些文件管理器)等功能的碎片。 - Denis Sologub

0

我有同样的问题。我想只在主Fragment中添加CollapsingToolbar。通过从Activity中删除Toolbar,我失去了汉堡按钮和对drawerLayout的连接。为了解决这个问题,我没有删除Activity中的工具栏,而是使其透明。并且对于每个Fragment,我都创建了自己的自定义工具栏。最后,我有一个与抽屉链接的汉堡按钮和一个功能良好的CollapsingToolbar。我知道这是一个权宜之计。但我找不到其他方法

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
    tools:context=".activity.MainActivity">

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

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

    <include
        android:id="@+id/include"
        layout="@layout/content_main"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

为了使AppBar完全不可见,我添加了以下代码。
AppBarLayout appBarLayout = findViewById(R.id.appbar);
appBarLayout.setOutlineProvider(null);

这适用于 Android sdk 版本 21。


-3
如果您正在使用DrawerLayoutNavigationView来创建导航抽屉,我认为最好的解决方案是为每个片段布局使用单独的DrawerLayout,并针对每个片段在DrawerLayout的主体中不同地使用AppBarLayout

1
这是唯一的解决方案吗?我需要重新附加几乎所有的视图层次结构。 - Denis Sologub
你必须明白,你试图改变的是一个body view而不是parent view,因为AppBarLayout仍然嵌入在DrawerLayout的body中。所以最好的做法是重新声明布局。如果你的NavigationView对于所有的fragment都是相同的,你可以将它写在一个单独的xml布局文件中,并使用<include layout="@layout/navigation_layout_name">来缩短你的代码。 - TeChNo_DeViL
好的,谢谢!我认为这个解决方案在片段切换上可能需要花费很多时间。但是我会使用它。 - Denis Sologub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接