如何使用底部导航视图和 Android 导航组件将参数传递给片段?
Posted
技术标签:
【中文标题】如何使用底部导航视图和 Android 导航组件将参数传递给片段?【英文标题】:How to pass arguments to a fragment using bottom navigation view and Android Navigation component? 【发布时间】:2019-06-02 13:39:51 【问题描述】:是否可以使用底部导航视图和导航组件在片段中传递和访问参数?
我正在使用具有多个片段的单一活动方法,其中我的***片段需要一个参数(通常通过 newInstance 生成的方法完成)。我查看了导航组件开发人员指南和代码实验室,但它只提到使用安全参数并在目的地和操作中添加参数标签。
这是我的导航图:
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/homeFragment">
<fragment android:id="@+id/homeFragment"
android:name="uk.co.homeready.homeready.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home">
<!--Do I create an argument block here?-->
</fragment>
<fragment android:id="@+id/calculatorFragment"
android:name="uk.co.homeready.homeready.CalculatorFragment"
android:label="fragment_calculator"
tools:layout="@layout/fragment_calculator"/>
<fragment android:id="@+id/resourcesFragment"
android:name="uk.co.homeready.homeready.ResourcesFragment"
android:label="fragment_resources"
tools:layout="@layout/fragment_resources"/>
</navigation>
底部导航视图菜单:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/homeFragment"
android:icon="@drawable/ic_home_black_24dp"
android:title="@string/title_home"/>
<item
android:id="@+id/calculatorFragment"
android:icon="@drawable/ic_baseline_attach_money_24px"
android:title="@string/title_calculator"/>
<item
android:id="@+id/resourcesFragment"
android:icon="@drawable/ic_baseline_library_books_24px"
android:title="@string/title_resources"/>
</menu>
主活动:
override fun onCreate(savedInstanceState: Bundle?)
...
val navController = Navigation.findNavController(this,
R.id.nav_host_fragment)
bottom_navigation.setupWithNavController(navController)
....
activity_main.xml
<android.support.constraint.ConstraintLayout>
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:layout_constraintBottom_toTopOf="@id/bottom_navigation"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"/>
<android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation"
app:menu="@menu/bottom_navigation"/>
</android.support.constraint.ConstraintLayout>
首页片段
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
val argument = //TODO access argument here
...
【问题讨论】:
所以你希望你的homeFragment
在你从底部导航点击它时以一些默认的参数集开始?您是在其他地方重用 homeFragment
并使用不同的参数,还是它们总是只是固定值?
是的,对于我的用例,我想在您点击底部导航时传递一些默认设置参数。我也可能在其他地方重用 homeFragment。
【参考方案1】:
如果我理解正确,您希望将参数传递给与菜单项相关的目的地。尝试在您的活动 onCreate 方法中使用“OnDestinationChangedListener”,如下所示:
navController.addOnDestinationChangedListener controller, destination, arguments ->
when(destination.id)
R.id.homeFragment ->
val argument = NavArgument.Builder().setDefaultValue(6).build()
destination.addArgument("Argument", argument)
更新:
如果您希望您的起始目的地接收默认参数,则实现应该不同。 首先,从 'NavHostFragment' xml 标记中删除 'app:navGraph="@navigation/nav_graph"'。
然后,在您的活动 onCreate 中,您需要对图表进行充气:
val navInflater = navController.navInflater
val graph = navInflater.inflate(R.navigation.nav_graph)
然后将您的参数添加到图形(此参数将附加到起始目的地)
val navArgument1=NavArgument.Builder().setDefaultValue(1).build()
val navArgument2=NavArgument.Builder().setDefaultValue("Hello").build()
graph.addArgument("Key1",navArgument1)
graph.addArgument("Key2",navArgument2)
然后将图表附加到 NavController:
navController.graph=graph
现在您的第一个目的地应该收到附加的参数。
【讨论】:
感谢亚历克斯的回答。我正在通过val argument = arguments?.getString("Argument")
检索 HomeFragment 中的参数但是在应用程序启动时 argument
在 HomeFragment 中为空,即使我可以看到正在调用侦听器并且正在主活动中创建参数。我必须点击底部导航中的另一个项目,然后点击并导航回 HomeFragment,以便 argument
返回一些内容
OnDestinationChangedListener
只在第二次起作用的原因是因为它是在navigate()
调用完成并且为第一个 Fragment 设置参数之后调用的。将<argument>
添加到图表中与在运行时手动创建NavArgument
完全相同,并且是推荐的方法。
我尝试了第一种方法,OnDestinationChangedListener 第一次没有工作。
@ianhanniballake 我遇到了同样的问题,OnDestinationChangedListener
第一次不起作用。我也通过 xml 将我的参数添加到了目的地,但它仍然不起作用。关于为什么的任何想法?【参考方案2】:
这样做的正确方法确实是在您的目的地上使用<argument>
块。
<fragment android:id="@+id/homeFragment"
android:name="uk.co.homeready.homeready.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home">
<argument
android:name="Argument"
android:defaultValue="value"
/>
</fragment>
这将使用默认值自动填充 Fragment 的参数,而无需任何额外的代码。从 Navigation 1.0.0-alpha09 开始,无论您是否使用 Safe Args Gradle 插件都是如此。
【讨论】:
如何在目标片段中接收这些参数? @NaumanAsh - the documentation 介绍了您如何接收参数,无论是否通过 Safe Args @ianhanniballake 当从bottomNavView
中点击一个项目时,我们能否以编程方式更改参数值?【参考方案3】:
默认值对我来说不可用,因为我有动态菜单项,其中可能有多个具有不同参数的相同目的地。 (从服务器更改)
实现BottomNavigationView.OnNavigationItemSelectedListener:
override fun onNavigationItemSelected(item: MenuItem): Boolean
val fragmentId = item.itemId
val arguments = argumentsByFragmentId[fragmentId] // custom mutableMapOf<Int, Bundle?>() with arguments
navController().navigate(fragmentId, arguments)
return true
要使用它,您将通过替换侦听器来接管导航。这里的调用顺序很重要:
bottomNavigationView.setupWithNavController(navController)
bottomNavigationView.setOnNavigationItemSelectedListener(this)
【讨论】:
以上是关于如何使用底部导航视图和 Android 导航组件将参数传递给片段?的主要内容,如果未能解决你的问题,请参考以下文章
如何将加载覆盖进度条覆盖到android的“底部导航视图”(使用约束布局)
如何保存底部导航片段的状态 - 具有单个导航图的 Android 导航组件