导航 UI 片段中带有折叠工具栏的架构

Navigation UI Architecture with collapsing toolbar in fragment

我正在使用现代架构组件构建我的应用程序。

这是我的主要activityXML

<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:id="@+id/relativeLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/main_app_bar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <com.google.android.material.appbar.MaterialToolbar
                android:id="@+id/main_tool_bar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:theme="@style/MaterialTheme"
                style="@style/Widget.MaterialComponents.Toolbar.Primary"
                app:titleTextColor = "@android:color/white"
                />

        </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/navigation_graph"
            android:layout_below="@id/main_app_bar_layout"/>

    </RelativeLayout>


    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@drawable/gradient_background"
        android:theme="@style/Theme.Design"
        app:itemTextColor="@android:color/white"
        app:menu="@menu/drawer_menu" />

</androidx.drawerlayout.widget.DrawerLayout>

这是我的主要 activity java 文件,说明我如何设置导航控制器


        DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);

        NavigationView navigationView = findViewById(R.id.navigation_view);

        MaterialToolbar mainToolBar = findViewById(R.id.main_tool_bar);

        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);

        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(R.id.wallet_fragment)
                .setOpenableLayout(drawerLayout)
                .build();

        NavigationUI.setupWithNavController(mainToolBar, navController, appBarConfiguration);

这是我的片段xml,带有折叠工具栏


<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=".fragments.WalletFragment">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Large"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:padding="5dp">

                <de.hdodenhof.circleimageview.CircleImageView
                    android:id="@+id/imv_display_pic"
                    android:layout_width="120dp"
                    android:layout_height="120dp"
                    android:layout_alignParentStart="true"
                    android:layout_alignParentLeft="true"
                    android:layout_centerInParent="true"
                    android:src="@drawable/ic_launcher"
                    app:civ_border_color="@android:color/white"
                    app:civ_border_width="2dp" />

                <RelativeLayout
                    android:id="@+id/relative_layout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_toEndOf="@+id/imv_display_pic"
                    android:layout_toRightOf="@+id/imv_display_pic">

                    <TextView
                        android:id="@+id/tv_wallet_balance"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="10dp"
                        android:layout_marginLeft="10dp"
                        android:text="Ksh 1000"
                        android:textAppearance="@style/TextAppearance.AppCompat.Display1"
                        android:textColor="@android:color/white" />

                    <TextView
                        android:id="@+id/tv_display_wallet_balance"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_below="@id/tv_wallet_balance"
                        android:layout_marginStart="10dp"
                        android:layout_marginLeft="10dp"
                        android:text="Wallet Balance"
                        android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

                </RelativeLayout>

            </RelativeLayout>

            <com.google.android.material.appbar.MaterialToolbar
                android:id="@+id/wallet_tool_bar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:title="Username" />

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

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

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal">

            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_add_money"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="2dp"
                android:layout_marginLeft="2dp"
                android:layout_marginTop="2dp"
                android:layout_marginBottom="2dp"
                android:text="Add Money"
                android:textColor="@android:color/white"
                android:theme="@style/ButtonsTheme"
                app:icon="@drawable/ic_add_money"
                app:iconTint="@android:color/white"
                android:textAllCaps="false"/>

            <com.google.android.material.button.MaterialButton
                android:id="@+id/btn_withdraw_money"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="2dp"
                android:layout_marginLeft="2dp"
                android:layout_marginTop="2dp"
                android:layout_marginBottom="2dp"
                android:layout_toEndOf="@+id/btn_add_money"
                android:layout_toRightOf="@+id/btn_add_money"
                android:text="Withdraw Money"
                android:textColor="@android:color/white"
                android:theme="@style/ButtonsTheme"
                app:icon="@drawable/ic_withdraw"
                app:iconTint="@android:color/white"
                android:textAllCaps="false" />

        </RelativeLayout>

    </androidx.core.widget.NestedScrollView>


</androidx.coordinatorlayout.widget.CoordinatorLayout>

我遇到的问题是,当现在加载片段时,我如何将折叠工具栏中的 material 工具栏设为主工具栏,它显示两个工具栏,主工具栏中的一个 activity 和片段中的那个 .

我已经尝试在此处实施解决方案:https://developer.android.com/guide/navigation/navigation-ui#support_app_bar_variations

这是我尝试在片段 java class

中实现的方式
    NavController navController = Navigation.findNavController(view);
    AppBarConfiguration appBarConfiguration =
            new AppBarConfiguration.Builder(navController.getGraph()).build();
    MaterialToolbar walletToolBar = view.findViewById(R.id.wallet_tool_bar);

    NavigationUI.setupWithNavController(
            walletToolBar , navController, appBarConfiguration);

我试过了,但它仍然显示主要 activity 和片段

的工具栏

我一直在为同样的问题苦苦挣扎,终于找到了解决方案。

首先,您需要从 activity 中删除工具栏,并为每个需要它的片段添加单独的工具栏,如 google 文档中所述。

对于您的情况,只需从 activity 的布局中删除工具栏声明:

<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:id="@+id/relativeLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <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/navigation_graph"
            android:layout_below="@id/main_app_bar_layout"/>

    </RelativeLayout>
...

之后,您需要 link 每个片段的工具栏都带有主导航抽屉,但在此之前,您需要在 activity 中进行一些更改。

首先从activity的onCreate方法中删除NavigationUI.setupWithNavController(mainToolBar, navController, appBarConfiguration);行,因为此时不会创建任何工具栏。您还需要让所有片段都可以访问您的 drawerLayout,因此您需要为此创建 public 变量(但您可以使用任何其他方式,您只需要同时访问片段的工具栏和 activity的抽屉布局)。最后你的 activity 的代码应该是这样的:

public class MainActivity extends AppCompatActivity {
    public DrawerLayout drawerLayout = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        drawerLayout = findViewById(R.id.drawer_layout);
    }
    ...

最后,要将 fragment 的工具栏与 activity 的 NavigationUI 连接,您需要将这段代码添加到每个 fragment class(这可能很麻烦,我不知道 java,但在 kotlin 中我确实使用了扩展函数来避免这种情况):

public class SomeFragment extends Fragment {
    ...

    // You may have used onActivityCreated instead
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        
        setupToolbar();
    }
    
    private void setupToolbar() {
        NavController navController = findNavController(R.id.nav_host_fragment);
        Toolbar toolbar = findViewById<Toolbar>(R.id.wallet_tool_bar);

        MainActivity activity = (MainActivity) getActivity();

        toolbar.setupWithNavController(navController, activity.drawerLayout);

        activity.setSupportActionBar(toolbar);
        activity.getActionBar().setDisplayHomeAsUpEnabled(true);
    }
    ...
}

本文的关键部分是 toolbar.setupWithNavController(navController, drawerLayout); 行,其中 link 片段的工具栏与 activity 的抽屉布局。

我没有测试这段代码,因为我专门使用 kotlin,所以你应该把它当作一个表示而不是完整的代码。

P.S。抱歉我的英语不好。

首先我们在themes.xml或styles.xml

设置主题
    <style name="Theme.AppTheme" parent="Theme.MaterialComponents.DayNight">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/primaryColor</item>
        <item name="colorPrimaryVariant">@color/primaryDarkColor</item>
        <item name="colorOnPrimary">@color/primaryLightColor</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/secondaryColor</item>
        <item name="colorSecondaryVariant">@color/secondaryDarkColor</item>
        <item name="colorOnSecondary">@color/secondaryLightColor</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
        <item name="actionBarTheme">@style/ActionBarTheme</item>

    </style>

    <style name="ActionBarTheme" parent="Theme.MaterialComponents.DayNight">

        <item name="colorPrimary">@color/primaryColor</item>
        <item name="colorPrimaryVariant">@color/primaryDarkColor</item>
        <item name="colorOnPrimary">@color/primaryLightColor</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/secondaryColor</item>
        <item name="colorSecondaryVariant">@color/secondaryDarkColor</item>
        <item name="colorOnSecondary">@color/secondaryLightColor</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>

        <!--Toolbar text color-->
        <item name="android:textColorPrimary">@android:color/white</item>

        <!-- action menu item icon color -->
        <item name="colorControlNormal">@android:color/white</item>

    </style>

然后在Manifest里面的application标签


android:theme="@style/Theme.AppTheme"

MainActivityXML实现

<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <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/navigation_graph"/>

    </RelativeLayout>

    <!--app:headerLayout="@layout/nav_header"-->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="230dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@drawable/nav_view_background"
        android:fitsSystemWindows="true"
        app:itemTextColor="@android:color/white"
        app:itemIconTint="@android:color/white"
        android:theme="@style/Theme.AppCompat.DayNight"
        app:menu="@menu/drawer_menu">

    </com.google.android.material.navigation.NavigationView>


</androidx.drawerlayout.widget.DrawerLayout>

MainActivityjava文件实现


    DrawerLayout drawerLayout;
    NavigationView navigationView;
    AppBarConfiguration appBarConfiguration;
    NavController navController;

    ActionBarDrawerToggle navDrawerToggle;

   // Inside onCreate method 

        drawerLayout = findViewById(R.id.drawer_layout);

        navigationView = findViewById(R.id.navigation_view);

        navController = Navigation.findNavController(this, R.id.nav_host_fragment);

        navDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, "open", "close");

        drawerLayout.addDrawerListener(navDrawerToggle);
        navDrawerToggle.setDrawerIndicatorEnabled(true);
        navDrawerToggle.syncState();

        appBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_wallpapers_fragment)
                .setOpenableLayout(drawerLayout)
                .build();

        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);

        NavigationUI.setupWithNavController(navigationView, navController);

具有折叠工具栏的片段 XML 实现

<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"
    android:background="@color/colorWhiteShade"
    tools:context=".fragments.WallpaperDetailsFragment">

    <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/app_bar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fitsSystemWindows="true"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <!--        Change height of the collapsing toolbar here-->
            <!--To make the expanded title appearance to transparent-->
    <!--        app:expandedTitleTextAppearance="@android:color/transparent"-->
            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                app:contentScrim="?attr/colorPrimary"
                android:fitsSystemWindows="true"
                app:layout_scrollFlags="scroll|exitUntilCollapsed"
                app:expandedTitleTextAppearance="@android:color/transparent">

                <ImageView
                    android:id="@+id/imageview"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:scaleType="centerCrop"
                    android:contentDescription="@string/wallpaper_collapsing_toolbar"/>

                <androidx.appcompat.widget.Toolbar
                    android:id="@+id/toolbar"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    app:layout_collapseMode="pin"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:title="Toolbar Title"/>

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

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

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clipToPadding="false"
        android:scrollbars="none"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
      
            // Create your views here

        </RelativeLayout>

    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

具有折叠工具栏的片段

    AppBarLayout appBarLayout;

    CollapsingToolbarLayout collapsingToolBarLayout;

    Toolbar toolbar;

    DrawerLayout drawerLayout;

    // In onCreate method

     @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Objects.requireNonNull(((MainActivity) requireActivity()).getSupportActionBar()).hide();

    }

   // In onViewCreated method 

        appBarLayout= view.findViewById(R.id.app_bar_layout);
        CollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar_layout);
        toolbar= view.findViewById(R.id.toolbar);

         AppBarConfiguration appBarConfiguration =
                new AppBarConfiguration.Builder(navController.getGraph()).build();

        NavigationUI.setupWithNavController(
                toolbar, navController, appBarConfiguration);

        NavigationUI.setupWithNavController(CollapsingToolbarLayout , toolbar, navController);