点击FAB后导航到片段(导航架构组件)

16

我不知道如何使用新的导航架构组件,从我的主屏幕(带有附加到BottomAppBar上的FloatingActionButton)导航到另一个没有应用栏的屏幕。

当我点击FloatingActionButton时,我希望我的下一个屏幕(片段?)从右侧滑入。问题是我要把BottomAppBar放在哪里?如果我将它放在我的MainActivity中,那么我会遇到FloatingActionButton没有设置NavController的问题。我也无法将BottomAppBar放在我的片段中。我感到很困惑。

5个回答

30
今天遇到了这个问题,我发现有一个简单而优雅的解决方案。
val navController = findNavController(R.id.navHostFragment)

fabAdd.setOnClickListener {
   navController.navigate(R.id.yourFragment)
}  

这样就处理了导航。然后你必须控制ActivityBottomAppBar的可见性。


1
你不需要这行代码 Navigation.setViewNavController(fabAdd, navController) - 只有在你想使用 fabAdd.findNavController() 时才需要它(而且,由于你已经有了对 NavController 的引用,这是你永远不需要做的事情)。 - ianhanniballake
谁比它的创造者更了解这个伟大的API呢!感谢ianhanniballake提供如此棒的库和您的评论。我会删除那一行的。 - Dariush Malek
这会导致“类型不匹配。需要:Fragment 找到:Int”。 - bakero98
好的,我找到了一个解决方案,不会破坏 BottomAppBar。请查看我的答案。 - bakero98
@DariushMalek 出现错误:“Activity没有设置NavController”。我不明白,我正在使用FragmentContainerView。 - Mehmet Gür
显示剩余2条评论

6
您可以将BottomAppBar放置在MainActivity中,并通过以下方式在您的片段中访问FloatingActionButton
activity?.fab?.setOnClickListener { 
    /*...*/
    findNavController().navigate(R.id.action_firstFragment_to_secondFragment, mDataBundle)
}

您可以按照以下方式从另一个活动中隐藏BottomAppBar
(activity as AppCompatActivity).supportActionBar?.hide()

确保在返回到前一个片段时,.show() BottomAppBar。


1
将其放入MainActivity中,并在活动的onStart()中设置setOnClickListener,它将正常工作。
override fun onStart() {
  super.onStart()
  floatingActionButton.setOnClickListener {
    it.findNavController().navigate(R.id.yourFragment)
   }
}

注意:这个解决方案类似于黑客技巧,更好的方法是遵循Activity LifeCycle并在活动准备好交互时设置OnClickListener。
类似问题已得到解决。(链接)

1
如果出于某些原因您想要导航到特定的片段(而不是星形片段),并且您有一个活动的两个图表,这是我建议的方法: 此方法将启动活动。
companion object {

        const val REQUEST_OR_CONFIRM = "request_or_confirm"
        const val IS_JUST_VIEW = "IS_JUST_VIEW"
        const val MODEL = "model"

        fun open(activity: Activity, isRequestOrConfirm: Boolean, isJustView: Boolean = false, model: DataModel? = null) {
            val intent = Intent(activity, HostActivity::class.java)
            intent.putExtra(REQUEST_OR_CONFIRM, isRequestOrConfirm)
            intent.putExtra(IS_JUST_VIEW, isJustView)
            intent.putExtra(MODEL, model)
            activity.startActivity(intent)
        }
    }

在主活动的onCreate方法中,首先决定使用哪个图形,然后传递意图附加信息包,以便启动片段可以决定要做什么:
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_purchase_nav)
        if (intent.getBooleanExtra(REQUEST_OR_CONFIRM, true)) {
            findNavController(R.id.nav_host_fragment).setGraph(R.navigation.nav_first_scenario, intent.extras)
        } else {
            findNavController(R.id.nav_host_fragment).setGraph(R.navigation.nav_second_scenario, intent.extras)
        }
    }

以下是如何在起始片段中决定要执行的操作:

if (arguments != null && arguments!!.getBoolean(HostActivity.IS_JUST_VIEW)){
    navigateToYourDestinationFrag(arguments!!.getParcelable<DataModel>(HostActivity.MODEL))
}

然后像平常一样导航:
private fun navigateToYourDestinationFrag(model: DataModel) {
        val action = StartFragmentDirections.actionStartFragmentToOtherFragment(model)
        findNavController().navigate(action)
    }

如果您想从一开始就跳转到第三个片段,您的图表可能如下所示: enter image description here

附注:请确保在第三个片段上处理返回按钮,这里有一个解决方案

更新: 正如EpicPandaForce所提到的那样,您也可以使用导航组件启动活动: 要做到这一点,首先将活动添加到现有的图表中,可以通过+图标(对我无效)或手动在xml中添加来完成:

 <activity
        android:id="@+id/secondActivity"
        tools:layout="@layout/activity_second"
        android:name="com.amin.SecondActivity" >
    </activity>

您还可以添加参数,并像在片段中一样使用它们,使用navArgs()。

 <activity
        android:id="@+id/secondActivity"
        tools:layout="@layout/activity_second"
        android:name="com.amin.SecondActivity" >
        <argument
            android:name="testArgument"
            app:argType="string"
            android:defaultValue="helloWorld" />
    </activity>

在 Kotlin 中,以下是如何使用参数的方法。首先,在你的活动类顶部声明 args 变量,变量类型为以你的活动命名的生成类,例如本例中的 SecondActivityArgs:
val args: SecondActivityArgsby by navArgs()

然后你可以像这样使用它:

print(args.testArgument)

2
我认为你不再需要手动启动Activity,因为你可以使用“ActivityDestination”。 - EpicPandaForce

0
这不会破坏底部应用栏。只需将此添加到主活动(MainActivity)中,不要做任何其他操作。
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment

fabAdd.setOnClickListener {
   findNavController(navHostFragment).navigate(R.id.fab)
} 

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