Как передать аргументы во фрагмент, используя вид нижней навигации и компонент навигации Android?
Можно ли передать и получить доступ к аргументам во фрагменте, используя нижнее представление навигации и компонент навигации?
Я использую подход с одним действием со многими фрагментами, где мой фрагмент верхнего уровня требует аргумента (обычно это делается с помощью сгенерированного метода newInstance). Я взглянул на руководство разработчика компонента навигации и кодовую метку, но в нем упоминается только использование safeargs и добавление тегов аргументов в местах назначения и действиях.
Вот мой график навигации:
<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>
HomeFragment
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val argument = //TODO access argument here
...
}
4 ответа
Если я вас правильно понял, вы хотите передать аргументы адресатам, привязанным к пунктам меню. Попробуйте использовать 'OnDestinationChangedListener' внутри метода своей деятельности onCreate, что-то вроде этого:
navController.addOnDestinationChangedListener { controller, destination, arguments ->
when(destination.id) {
R.id.homeFragment -> {
val argument = NavArgument.Builder().setDefaultValue(6).build()
destination.addArgument("Argument", argument)
}
}
}
Обновить:
Если вы хотите, чтобы ваш начальный пункт назначения получал аргументы по умолчанию, реализация должна отличаться. Сначала удалите 'app:navGraph="@navigation/nav_graph"' из своего xml-тега NavHostFragment.
Затем, внутри вашей деятельности на Create вам нужно надуть график:
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
Теперь ваш первый пункт назначения должен получить прикрепленные аргументы.
Правильный способ сделать это действительно с <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>
Это автоматически заполнит аргументы фрагмента значением по умолчанию без необходимости в дополнительном коде. Начиная с версии 1.0.0-alpha09, это верно независимо от того, используете ли вы Safe Args Gradle Plugin или нет.
Я не мог использовать значения по умолчанию, потому что у меня есть элементы динамического меню, которые могут иметь несколько одинаковых пунктов назначения с разными аргументами. (изменено с сервера)
Реализуйте 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)
Мой аргумент уже был определен в XML-файле навигационного графа, и я не знаю, почему, но ответ @Alex у меня не сработал, вместо этого я сделал это (из назначенияChangedListener):
arguments?.putParcelable("argname", argvalue)
Обратите внимание, что я использовал это, чтобы дать конкретный ответ при глубокой ссылке на определенную вкладку панели навигации. По умолчанию мне также нужно было сделать это (чтобы избежать повторного использования одного и того же пакета и повторной обработки глубоких ссылок):
arguments?.remove("argname")