问题描述
我正在尝试将 NavigationDrawer 与具有刷新菜单选项的工具栏结合起来:
我的 MainActivity
只有一个 Fragment。 activity_main.xml
:
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_nav_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main" />
MainActivity.kt
:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
nav_main
:
<navigation 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/nav_main"
app:startDestination="@id/drawerFragment"
>
<fragment
android:id="@+id/drawerFragment"
android:name="com.example.rocketman.drawer.DrawerFragment"
android:label="DrawerFragment"
tools:layout="@layout/fragment_drawer"
/>
</navigation>
基本上我的 MainActivity 直接导航到 DrawerFragment,它在这里:
<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"
android:orientation="vertical"
tools:context="com.example.rocketman.drawer.DrawerFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.rocketman.drawer.DrawerFragment">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/midnight_blue"
app:titleTextColor="@color/white"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/drawer_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/drawer_nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/drawer_header"
app:menu="@menu/drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
最后,我的DrawerFragment
:
private const val KEY_SELECTED_DRAWER_ITEM = "DRAWER_SELECTED_ITEM_ID_KEY"
class DrawerFragment: Fragment() {
private lateinit var binding: FragmentDrawerBinding
private var drawerSelectedItemId = R.id.nav_home
override fun onCreateView(
inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
): View {
binding = FragmentDrawerBinding.inflate(inflater)
(requireActivity() as AppCompatActivity).setSupportActionBar(toolbar_home)
return binding.root
}
override fun onViewCreated(view: View,savedInstanceState: Bundle?) {
super.onViewCreated(view,savedInstanceState)
savedInstanceState?.let {
drawerSelectedItemId = it.getInt(KEY_SELECTED_DRAWER_ITEM,drawerSelectedItemId)
}
setupDrawer()
setBackpressedHandler()
}
private fun setBackpressedHandler() {
requireActivity().onBackpresseddispatcher.addCallback(viewLifecycleOwner) {
if (binding.drawerLayout.isOpen) {
binding.drawerLayout.close()
} else {
findNavController().popBackStack()
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(KEY_SELECTED_DRAWER_ITEM,drawerSelectedItemId)
super.onSaveInstanceState(outState)
}
private fun setupDrawer() {
val controller = binding.drawerNavView.setupWithNavController(
childFragmentManager,findNavController(),listof(
//all the items on the Drawer have their own navigation graph
R.navigation.home,R.navigation.rocket,R.navigation.company
),R.id.drawer_container,drawerSelectedItemId,requireActivity().intent
)
controller.observe(
viewLifecycleOwner,{ navController ->
NavigationUI.setupWithNavController(
binding.toolbarHome,navController,binding.drawerLayout
)
drawerSelectedItemId = navController.graph.id
}
)
}
}
换句话说,Drawer 有三个项目:home
、rocket
和 company
,如下所示,menu/drawer
:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/nav_home"
android:checked="true"
android:checkable="true"
android:icon="@drawable/ic_home"
android:title="@string/nav_menu_home"
/>
<item
android:id="@+id/nav_rocket"
android:checkable="true"
android:icon="@drawable/ic_rocket"
android:title="@string/nav_menu_rocket_list"
/>
<item
android:id="@+id/nav_company"
android:checkable="true"
android:icon="@drawable/ic_company"
android:title="@string/nav_menu_company_data"
/>
</menu>
home
、rocket
和 company
都有自己的导航图,例如 navigation/company
如下所示:
<navigation 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/nav_company"
app:startDestination="@id/companyDataFragment">
<fragment
android:id="@+id/companyDataFragment"
android:name="com.example.rocketman.company.CompanyFragment"
android:label="@string/nav_menu_company_data"
tools:layout="@layout/fragment_company_data"
/>
</navigation>
而且 CompanyFragment
很简单:
class CompanyFragment: Fragment() {
private lateinit var binding: FragmentCompanyDataBinding
private val vm by lazy {
viewmodelProvider(this).get(CompanyVM::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
Repo.init(requireContext())
}
override fun onCreateView(
inflater: LayoutInflater,savedInstanceState: Bundle?
): View {
binding = FragmentCompanyDataBinding.inflate(inflater)
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu,inflater: MenuInflater) {
super.onCreateOptionsMenu(menu,inflater)
inflater.inflate(R.menu.company,menu)
}
override fun onViewCreated(view: View,savedInstanceState)
setupObservers()
}
private fun setupObservers() {
//observing
}
}
那部分有效。
但是,我想为 Company
创建一个菜单操作。所以首先我创建一个菜单项 menu/company
:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/update"
android:icon="@drawable/ic_baseline_refresh_24"
android:title="@string/menu_company_update"
app:showAsAction="ifRoom|withText"
/>
</menu>
然后在 CompanyFragment
中我调用 override onCreate() { setHasOptionsMenu(true) }
和 override onCreateOptionsMenu() { inflater.inflate(R.menu.company,menu }
。
这应该为工具栏创建选项菜单。但是,Fragment 只显示抽屉菜单图标,而不显示选项菜单图标。
我可以向内容片段本身添加一个工具栏,但该应用程序有两个工具栏,一个带有抽屉,另一个带有选项:
如何使工具栏同时具有 NavigationDrawer 和选项项?
解决方法
据我从您的问题中了解到,您希望显示溢出菜单和抽屉菜单。
菜单 xml 文件中的 showAsAction 选项可用于控制单个菜单选项在操作栏中的显示方式。
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/update"
android:icon="@drawable/ic_baseline_refresh_24"
android:title="@string/menu_company_update"
app:showAsAction="ifRoom|withText"
/>
</menu>
改成
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/update"
android:icon="@drawable/ic_baseline_refresh_24"
android:title="@string/menu_company_update"
app:showAsAction="never"
/>
</menu>
这将显示溢出菜单中的菜单项。
,仍然有很多人继续使用ActionBar,我们不必再使用它了。如果我是你,我不会使用 ActionBar 和与 ActionBar 相关的 setHasOptionsMenu(true)
,而只会使用工具栏。
只需删除 setHasOptionsMenu(true)
、onCreateOptionsMenu()
和 onOptionsItemSelected()
(如果有)。
相反,直接在工具栏上使用 Toolbar.inflateMenu()
和 Toolbar.setOnMenuItemClickListener()
。