android - 使用导航组件为每个 fragment 自定义工具栏

标签 android kotlin android-fragments android-toolbar android-architecture-navigation

我将导航组件用于单个 Activity 。为每个 fragment 创建自定义工具栏的想法。例如,一个工具栏必须是黄色的,另一个带有菜单图标的紫色工具栏,另一个是透明的。如果可能的话,我想通过 MainActivity 中的 setupActionBarWithNavController(navController) 保存导航和工具栏之间的连接来实现它。 我尝试在 Fragment 中使用此方法 (activity as?AppCompatActivity)?.setSupportActionBar(toolbar) 但它复制了工具栏。

这是我的主题

<style name="Theme.Movies" parent="Theme.MaterialComponents.DayNight.NoActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_500</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>

这是MainActivity布局中的工具栏

 <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/purple_700"
        android:elevation="4dp"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:layout_constraintTop_toTopOf="parent" />

这是 MainActivity

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        setSupportActionBar(toolbar)

        val navHostFragment =
            supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment

        navController = navHostFragment.navController

        setupActionBarWithNavController(navController)
        bottom_nav.setupWithNavController(navController)

    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
}

最佳答案

I tried to use this method (activity as? AppCompatActivity)?.setSupportActionBar(toolbar) in Fragment but it duplicated toolbar.

这是预期的,因为工具栏由 Activity 托管,并且由于 Jetpack 导航架构组件使用单 Activity 模型,因此此 Activity 托管的所有 navGraph fragment 共享此工具栏(因为它是 Activity 的一部分)。

因此再次重置工具栏将复制它。

这个问题的解决方案是从 Activity 中删除工具栏,并在每个 fragment 布局中使用唯一的工具栏,这样当一个 fragment 被交易到另一个 fragment 时;旧 fragment 的布局被新 fragment 的新布局所取代,所以旧的工具栏不见了,我们有了一个新的工具栏;而此时你需要为新的工具栏调用setSupportActionBar(toolbar)

但请注意,每次调用 setSupportActionBar(toolbar) 时,您都必须调用 setupActionBarWithNavController(),因为它需要附加到新的工具栏。

更新

So, I have to call setSupportActionBar(toolbar) and setupActionBarWithNavController() in Fragment?

实际上你可以在 Activity 中调用setSupportActionBar(toolbar)。但是您可以在 fragment 中使用 requireActivity() 来做到这一点:

为了不重复事情,你可以有一个 Activity 的功能来做到这一点:

Activity 中:

fun setupActionBar(toolBar: Toolbar) {

    setSupportActionBar(toolbar)

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment

    navController = navHostFragment.navController

    setupActionBarWithNavController(navController)
    
}   

在 fragment 中:

val toolbar = findViewById<Toolbar>(R.id.foo)
(requireActivity() as MainActivity).setupActionBar(toolbar)

关于android - 使用导航组件为每个 fragment 自定义工具栏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68138959/

相关文章:

android - 如何使用 okhttp 进行本地测试

android - android中的自定义 ListView

android - 当第二个 Activity 方向改变时 registerForActivityResult 不起作用

android - 如何停止在单击操作项时从先前添加的 Fragment 调用 onOptionsItemSelected?

android - 当 Api 级别为 24 时,文本颜色在 xml 中不起作用

java - 新补丁后 Android Studio 无法启动

android - ROOM 无法弄清楚如何将此字段保存到数据库中

手机屏幕关闭时Android导航架构无法导航

java - Android 调用带有 onClick 错误的 fragment 方法

安卓 : Fullscreen system visibility screws up window insets