微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

导航组件-仅活动中的ActionBar句柄

如何解决导航组件-仅活动中的ActionBar句柄

我终于在一个新项目中采用了导航体系结构组件,并且我已经遇到了一些文档似乎无法解决的问题。

在活动中设置了ActionBar菜单后,当我导航到另一个片段然后尝试使用收到的ActionBar菜单

java.lang.IllegalArgumentException: Navigation action/destination X cannot be found from the current destination

看来,我还必须将所有可能的目标位置的动作添加到所有其他目标位置,这似乎有些过分,但这不可能。对于我找不到的问题,必须有解决方案。

我打算打开对MainActivity进行扩展的应用程序,然后对fragment元素中的MainFragment进行扩展。 MainActivity仍应在ActionBar中处理顶级导航。绝对没有必要在每个片段中重复菜单单击操作并为应用程序所有其他区域定义目标。

MainActivity

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()
    }
}

activity_main

<?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>

MainFragment

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,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())
        }
    }
}

fragment_main

<?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>

DashboardFragment

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,savedInstanceState)

        _binding = FragmentDashboardBinding.inflate(inflater,false)
        mView = binding.root
        mActivity = (activity as MainActivity)

        return mView
    }
}

fragment_dashboard

<?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>

nav_graph

<?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>

appbar_menu

<?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)
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。