导航组件,控制何时显示汉堡菜单或返回图标。

32

我有以下活动

class MainActivity : AppCompatActivity() {

private lateinit var drawerLayout: androidx.drawerlayout.widget.DrawerLayout

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_activity)

    drawerLayout = drawer_layout

    val navController = Navigation.findNavController(this, R.id.fragment_main_navHost)

    setSupportActionBar(toolbar)

    NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
    navView_main.setupWithNavController(navController)
}

override fun onSupportNavigateUp(): Boolean {
    return NavigationUI.navigateUp(drawerLayout,
        Navigation.findNavController(this, R.id.fragment_main_navHost))
}

override fun onBackPressed() {
    if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
        drawerLayout.closeDrawer(GravityCompat.START)
    } else {
        super.onBackPressed()
    }
}

如您所见,它与导航图相关联,并且我正在使用抽屉式导航菜单。当我通过抽屉中的项进行导航时,我希望保留汉堡包图标,并且仅在单击片段或弹出窗口中的项目时将其更改为上/返回按钮,并确保系统的行为基于显示的图标符合用户的期望。这可能吗?

3个回答

28
为控制AppBar导航上/返回何时显示,需要执行以下步骤:
1- 创建AppBarConfiguration并将顶级目标和drawerLayout传递给它。
    appBarConfiguration = AppBarConfiguration(
        setOf(
            R.id.dest_one,
            R.id.dest_two
        ),
        drawerLayout
    )

2- 告诉AppBar有关配置和导航。这将有助于显示标题并显示向上箭头或抽屉菜单图标。

setupActionBarWithNavController(navController, appBarConfig)

3- 最后重写onOptionsItemSelected和onSupportNavigateUp以及Navigation Component扩展程序,以告知AppBar如何行动

    override fun onOptionsItemSelected(item: MenuItem)= item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
        || super.onOptionsItemSelected(item)


override fun onSupportNavigateUp() = findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)

参考 Google Code Lab 导航 导航 CodeLab


我尝试了这段代码并定义了所有我的顶级目的地,但当我从一个顶级目的地移动到另一个片段时,会显示返回按钮,当单击工具栏的返回按钮时,抽屉将再次打开。我该如何解决这个问题? - Abraham Mathew
请问您能否分享一段代码片段或其他内容,以便我们了解您正在做什么? - Mustafa ALMulla
你能在Github上分享它并提供链接吗? - Mustafa ALMulla
其实我可以提出另一个问题并分享链接,这样可以吗? - Abraham Mathew
https://dev59.com/1TQBtIcB2Jgan1zn9qvM - Abraham Mathew

11

按照以下步骤操作

1. 将您的 NavigationViewNavigationUI 绑定

NavigationUI.setupWithNavController(nav_view, hostFragment.navController)

2. 绑定 NavControllerActionBar

NavigationUI.setupActionBarWithNavController(this@NavActivity, hostFragment.navController)

3. 使用 NavigationUI.setupActionBarWithNavControllerNavigationUI.setupWithDrawerLayout 方法将 ActionBarDrawerLayoutNavController 绑定。

NavigationUI.setupActionBarWithNavController(this@NavActivity, hostFragment.navController, drawer_layout)

4. 在您的活动中 override onSupportNavigateUp()

override fun onSupportNavigateUp(): Boolean {
    return NavigationUI.navigateUp(drawer_layout, hostFragment.navController) 
              || super.onSupportNavigateUp()
}

示例:

class NavActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {

    lateinit var hostFragment: NavHostFragment

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

        fab.setOnClickListener { view ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show()
        }

        val toggle = ActionBarDrawerToggle(
                this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
        drawer_layout.addDrawerListener(toggle)
        toggle.syncState()

        nav_view.setNavigationItemSelectedListener(this)

        hostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment    
        NavigationUI.setupWithNavController(nav_view, hostFragment.navController)    
        NavigationUI.setupActionBarWithNavController(this@NavActivity, hostFragment.navController)    
        NavigationUI.setupActionBarWithNavController(this@NavActivity, hostFragment.navController, drawer_layout)    
    }

    override fun onBackPressed() {
        if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
            drawer_layout.closeDrawer(GravityCompat.START)
        } else {
            super.onBackPressed()
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        return NavigationUI.navigateUp(drawer_layout, hostFragment.navController) || super.onSupportNavigateUp()
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        menuInflater.inflate(R.menu.nav, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        when (item.itemId) {
            R.id.action_settings -> return true
            else -> return super.onOptionsItemSelected(item)
        }
    }

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
        // Handle navigation view item clicks here.
        drawer_layout.closeDrawer(GravityCompat.START)
        return true
    }
}

输出

主屏幕片段:

Home Fragment

第二个片段:

Fragment Two

第三个片段:

Fragment Tree


1
谢谢您的尝试,但是您提供的步骤并非必需,并且产生了相同的结果。我应该能够控制在使用导航抽屉时要显示哪个图标。 - Mustafa ALMulla
1
原则上,导航抽屉应该具有横向导航功能,这意味着项目处于同一级别。因此,当我使用抽屉从一个项目移动到另一个项目时,片段应该被替换而不是添加到堆栈顶部。请参见https://material.io/design/navigation/understanding-navigation.html#lateral-navigation。最后一件事,您只需要进行第三步操作,如果您想让架构组件控制返回和向上行为,则还需要进行第四步操作。 - Mustafa ALMulla
3
当我点击返回箭头时,它显示导航抽屉而不是返回到之前的片段。 - AVEbrahimi
@AVEbrahimi 像我上面的代码一样,重写 onSupportNavigateUp() 方法。 - AskNilesh
当我点击返回箭头时,它显示导航抽屉而不是返回到先前的片段。- 有没有解决办法,我不想要一个变通方法。 - Abraham Mathew
当我点击返回箭头时,它显示导航抽屉而不是返回到先前的片段。只需添加toolbar.setupWithNavController(navController)即可。 - Anwar Zahid

3
因此,我认为您可以使用 NavController.OnNavigatedListener 来监听将要显示的片段,然后更新工具栏图标。
val navController = Navigation.findNavController(this, R.id.fragment_main_navHost)
navController.addOnNavigatedListener(contoller, destination -> {
   if(destination.id == R.id.fragmentTwo){
          // change the toolbar icon here
}
    })

很抱歉,我这里没有电脑,所以我在没有任何IDE的情况下编写了这段代码,可能会出现错误。但是请理解我的意图。

希望这能对你有所帮助。


虽然你的答案可能是一个解决方法,但我希望有一种自动化这个过程的解决方案。这将需要跟踪片段以知道要执行哪个操作。这样做会失去导航架构组件的好处。 - Mustafa ALMulla

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