android - 导航组件 - 仅限 Activity 中的 ActionBar 句柄
问题描述
我终于在一个新项目中采用了导航架构组件,我已经遇到了一些文档似乎没有解决的问题。
在活动中设置 ActionBar 菜单时,当我导航到另一个片段然后尝试使用我收到的 ActionBar 菜单时
java.lang.IllegalArgumentException: Navigation action/destination X cannot be found from the current destination
看来我还必须从所有可能的目的地添加动作以转到所有其他目的地,这似乎有点矫枉过正,这是不可能的。这个问题必须有一个我找不到的解决方案。
我打算打开在片段元素中膨胀 MainActivity 和 MainFragment 的应用程序。MainActivity 仍应处理 ActionBar 内的顶级导航。绝对没有理由我需要在每个片段中重复菜单点击工作并定义应用程序所有其他区域的目的地。
主要活动
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
private lateinit var appBarConfiguration: AppBarConfiguration
private var menu: Menu? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val controller by lazy { findNavController(R.id.fragment_container) }
navController = controller
val appBarConfig by lazy { AppBarConfiguration(navController.graph) }
appBarConfiguration = appBarConfig
setSupportActionBar(toolbar)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.appbar_menu, menu)
this.menu = menu
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
var direction: NavDirections? = null
when(item.itemId) {
R.id.action_messages -> {
direction = MainFragmentDirections.actionMainFragmentToMessagesFragment()
}
R.id.action_menu -> {
direction = MainFragmentDirections.actionMainFragmentToMessagesFragment()
}
else -> super.onOptionsItemSelected(item)
}
if (direction != null) navController.navigate(direction)
return true
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
活动主
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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/card_id_test"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="@color/colorPrimary"
android:elevation="4dp"
android:clipToPadding="false"
app:menu="@menu/appbar_menu"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:titleTextColor="@color/white" />
<fragment
android:id="@+id/fragment_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
app:layout_constraintTop_toBottomOf="@+id/toolbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
主要片段
class MainFragment : Fragment() {
private var _binding: FragmentMainBinding? = null
private val binding get() = _binding!!
private var mActivity : MainActivity? = null
private var mView: View? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
_binding = FragmentMainBinding.inflate(inflater, container, false)
mView = binding.root
mActivity = (activity as MainActivity)
return mView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_dashboard.setOnClickListener {
findNavController().navigate(
MainFragmentDirections.actionMainFragmentToDashboardFragment())
}
}
}
片段主
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content_test"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="Main Fragment"
android:textSize="24dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_dashboard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="Dashboard" />
</androidx.constraintlayout.widget.ConstraintLayout>
仪表板片段
class DashboardFragment : Fragment() {
private var _binding: FragmentDashboardBinding? = null
private val binding get() = _binding!!
private var mActivity : MainActivity? = null
private var mView: View? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
_binding = FragmentDashboardBinding.inflate(inflater, container, false)
mView = binding.root
mActivity = (activity as MainActivity)
return mView
}
}
片段仪表板
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content_test"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="Dashboard Fragment"
android:textSize="24dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
导航图
<?xml version="1.0" encoding="utf-8"?>
<navigation
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.appbarnavigation.MainFragment"
android:label="Main" >
<action
android:id="@+id/action_mainFragment_to_messagesFragment"
app:destination="@id/action_messages" />
<action
android:id="@+id/action_mainFragment_to_menuFragment"
app:destination="@id/action_menu" />
<action
android:id="@+id/action_mainFragment_to_dashboardFragment"
app:destination="@id/dashboardFragment" />
</fragment>
<fragment
android:id="@+id/action_messages"
android:name="com.example.appbarnavigation.MessagesFragment"
android:label="Messages" />
<fragment
android:id="@+id/action_menu"
android:name="com.example.appbarnavigation.MenuFragment"
android:label="Menu" />
<fragment
android:id="@+id/dashboardFragment"
android:name="com.example.appbarnavigation.DashboardFragment"
android:label="Dashboard" />
</navigation>
应用栏菜单
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_messages"
android:orderInCategory="1"
android:title="Messages"
android:icon="@drawable/ic_message"
app:showAsAction="always"/>
<item
android:id="@+id/action_menu"
android:orderInCategory="2"
android:title="Menu"
android:icon="@drawable/ic_menu"
app:showAsAction="always"/>
</menu>
解决方案
这是通过定义和使用全局操作来解决的。
<?xml version="1.0" encoding="utf-8"?>
<navigation
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.appbarnavigation.MainFragment"
android:label="Main" >
<action
android:id="@+id/action_mainFragment_to_dashboardFragment"
app:destination="@id/dashboardFragment" />
</fragment>
<fragment
android:id="@+id/action_messages"
android:name="com.example.appbarnavigation.MessagesFragment"
android:label="Messages" />
<fragment
android:id="@+id/action_menu"
android:name="com.example.appbarnavigation.MenuFragment"
android:label="Menu" />
<fragment
android:id="@+id/dashboardFragment"
android:name="com.example.appbarnavigation.DashboardFragment"
android:label="Dashboard" />
<action android:id="@+id/action_global_action_messages" app:destination="@id/action_messages" />
<action android:id="@+id/action_global_action_menu" app:destination="@id/action_menu" />
</navigation>
并在 MainActivity
override fun onOptionsItemSelected(item: MenuItem) = when(item.itemId) {
R.id.action_messages -> {
navController.navigate(R.id.action_global_action_messages)
true
}
R.id.action_menu -> {
navController.navigate(R.id.action_global_action_menu)
true
}
// This is used for menu buttons or anything not explicitly defined here
else -> {
super.onOptionsItemSelected(item)
}
}
推荐阅读
- javascript - Angular 6 - 在依赖注入之前使用异步调用初始化服务
- frameworks - podspec source 和 source_files 没有采用本地路径
- ubuntu - pip安装后找不到cget
- python - 如何传递python命令行参数?
- android - 在 Firebase Google Analytics 中看不到自定义广告系列参数结果
- reactjs - POST 未发送数据,在控制台中读取 OPTIONS
- php - WHERE 关键字在内部联接中不起作用
- reactjs - React Router v4 - 无法读取未定义的属性“参数”
- python-3.x - Pytorch 试图让 NN 收到无效的参数组合
- windows - 无法在批处理 scipt 中跟踪文件执行流程