基于Navigation Graph的Kotlin项目:实现CalendarioFragment到PdfFragment的按钮跳转
嘿,我来帮你搞定这个Fragment跳转的事儿!既然你已经用了Navigation Graph,那完全可以在CalendarioFragment本地实现跳转,而且这也是Navigation组件推荐的方式,比直接操作FragmentManager更简洁安全。下面一步步来修正你的代码:
第一步:修正Nav Graph配置里的冗余项
首先看你的Nav Graph代码,calendarioFragment和pdfFragment里的app:defaultNavHost="true"和app:navGraph="@navigation/mobile_navigation"是多余的——这些属性是给NavHostFragment用的,普通的业务Fragment不需要加。修正后的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" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/nav_graph" app:startDestination="@id/calendarioFragment"> <!-- 可根据你的需求调整起始页 --> <fragment android:id="@+id/calendarioFragment" android:name="com.example.aprimorandoconhecimentoss.ui.calendario.CalendarioFragment" android:label="fragment_calendario" tools:layout="@layout/fragment_calendario"> <action android:id="@+id/action_calendarioFragment_to_pdfFragment" app:destination="@id/pdfFragment" app:launchSingleTop="false" /> </fragment> <fragment android:id="@+id/pdfFragment" android:name="com.example.aprimorandoconhecimentoss.ui.pdf.PdfFragment" android:label="fragment_pdf" tools:layout="@layout/fragment_pdf"/> </navigation>
第二步:修正CalendarioFragment的跳转逻辑
你的Fragment代码里有两个小问题:一是没有正确使用View Binding,二是获取NavController的方式不对。下面是修正后的完整代码:
class CalendarioFragment : Fragment() { private var _binding: FragmentCalendarioBinding? = null private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { // 正确初始化View Binding,无需手动inflate布局 _binding = FragmentCalendarioBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 给按钮设置点击事件,通过NavController完成跳转 binding.botaoView1.setOnClickListener { // 调用Navigation Graph中定义好的跳转动作 findNavController().navigate(R.id.action_calendarioFragment_to_pdfFragment) } } override fun onDestroyView() { super.onDestroyView() _binding = null } }
关键说明:
- 不要自己声明
var navc = NavController,Fragment里可以直接用findNavController()方法(或view.findNavController())获取关联的NavController,这是Navigation组件的标准用法。 - 用View Binding获取按钮
botaoView1,比findViewById更安全高效,你之前手动inflate布局的方式浪费了Binding的优势。
第三步:检查MainActivity里的NavHost配置
你的MainActivity代码里同时找了R.id.calendarioFragment和R.id.nav_host_fragment_content_main两个NavHost,这会导致冲突。请确保你的Activity布局里只有一个NavHostFragment,并且它的id是nav_host_fragment_content_main,同时这个NavHostFragment的app:navGraph指向你的nav_graph.xml。
修正后的MainActivity核心代码可以简化成这样:
class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.appBarMain.toolbar) val drawerLayout: DrawerLayout = binding.drawerLayout val navView: NavigationView = binding.navView // 只获取布局里NavHostFragment对应的NavController val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration( setOf( R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow, R.id.nav_calendario_academico ), drawerLayout ) setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) } override fun onSupportNavigateUp(): Boolean { val navController = findNavController(R.id.nav_host_fragment_content_main) return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } }
为什么之前用supportFragmentManager会崩溃?
直接在Fragment里操作supportFragmentManager容易出问题,比如在Fragment还没完全依附到Activity的时候调用,或者跳转逻辑不符合Navigation的架构规范,导致Fragment栈混乱。而用NavController跳转是Navigation组件封装好的方式,会自动处理Fragment栈的管理,避免这类崩溃。
按照上面的步骤修改后,点击CalendarioFragment里的botaoView1按钮就能正常跳转到PdfFragment啦!
内容的提问来源于stack exchange,提问作者Fabricio Franco

