I'm currently writing an app with the new (to me) navigation component. I've got the basics down with a single navigation graph to navigate around my app, I've got a fragment with a BottomNavigationView in which has 3 seperate fragments, I've managed to update this to use the navigation component (as far as my problem) using the menu with ids that match the navigation items. My fragments which all previously used newInstance methods to pass a bundle to the onCreate are obviously now not used but I still need to pass a bundle to my fragments.
I haven't been able to find any examples of this being done, as the fragments are implicitly created.
My code is structured as ClientFragment which is the host fragment for the navigation drawer etc which is;
class ClientFragment : Fragment() {
private val viewModel: ClientViewModel by viewModel()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_client, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.client = arguments?.getParcelable(ARG_CLIENT)!!
toolbar_client.title = viewModel.client.name
toolbar_client.setNavigationOnClickListener { Navigation.findNavController(view).navigateUp() }
}
}
This class previously held on onclick listener to my fragments, with a newInstance method which tool viewModel.client.
My fragments in the nav_graph are all similar. The first fragment;
class ClientDetailsFragment : Fragment() {
private val viewModel: ClientViewModel by viewModel()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_client_details, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// viewModel.client = arguments?.getParcelable(ARG_CLIENT)!!
initClientDetails()
}
private fun initClientDetails() {
// text_client_details_name.text = viewModel.client.name
// text_client_details_account_number.text = viewModel.client.accountNumber
// text_client_details_mobile_number.text = viewModel.client.mobileNumber
// text_client_details_landline_number.text = viewModel.client.landlineNumber
// text_client_details_email.text = viewModel.client.email
// text_client_details_address.text = "NOT YET IMPLEMENTED"
//
// text_client_description_body.text = viewModel.client.description
// text_client_system_details_body.text = viewModel.client.systemDetails
}
}
The app crashes on the commented out line;
// viewModel.client = arguments?.getParcelable(ARG_CLIENT)!!
My navigation graph and menu are;
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/client_nav_graph"
app:startDestination="@id/clientDetailsFragment">
<fragment
android:id="@+id/clientCustomersFragment"
android:name="com.management.engineering.alarm.alarmengineermanagement.features.client.ClientCustomersFragment"
android:label="ClientCustomersFragment"
tools:layout="@layout/fragment_client_customers" />
<fragment
android:id="@+id/clientDetailsFragment"
android:name="com.management.engineering.alarm.alarmengineermanagement.features.client.ClientDetailsFragment"
android:label="ClientDetailsFragment"
tools:layout="@layout/fragment_client_details"/>
<fragment
android:id="@+id/clientJobHistoryFragment"
android:name="com.management.engineering.alarm.alarmengineermanagement.features.client.ClientJobHistoryFragment"
android:label="ClientJobHistoryFragment"
tools:layout="@layout/fragment_client_job_history" />
</navigation>
menu;
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/clientDetailsFragment"
android:icon="@drawable/ic_launcher_foreground"
android:title="Details"/>
<item
android:id="@+id/clientJobHistoryFragment"
android:icon="@drawable/ic_launcher_foreground"
android:title="Job History"/>
<item
android:id="@+id/clientCustomersFragment"
android:icon="@drawable/ic_launcher_foreground"
android:title="Customers"/>
</menu>
I have found that you can add arguments to the navigation graph, but have found nothing about where to put them for this specific scenario, I'm also aware of being able to manual add bundles when navigating using .navigate.
Is there a way for me to set in my ClientFragment the arguments for each of these fragments to be
viewModel.client
Update:
My argument issue was solved by using a view model that's shared between all of the fragments in the BottomNavigationView (I realised this as I was typing the issue out to my friend) and the navigation itself I added this to the ClientFragment;
bottom_nav_client.setupWithNavController(
Navigation.findNavController(
view.findViewById<View>(R.id.fl_client_nav_container)
)
)
and my xml for fragment_client;
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar_client"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="?attr/NavigationBackIconLight"
app:titleTextColor="@color/white" />
<fragment
android:id="@+id/fl_client_nav_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottom_nav_client"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_client"
app:navGraph="@navigation/client_nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav_client"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?android:attr/windowBackground"
app:itemBackground="@color/colorPrimary"
app:itemIconTint="@drawable/bottom_nav_color"
app:itemTextColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/client_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
This is combined with the same navigation graph and menu as shown above.
The Codelabs referred to in the accepted answer don't mention passing arguments to fragments in the BottomNavigationView.
Override the OnNavigationItemSelectedListener set by the setupWithNavController() with a custom one:
val args = Bundle()
bottomNavigationView.setupWithNavController(navController)
bottomNavigationView.setOnNavigationItemSelectedListener { item ->
navController.navigate(item.itemId, args)
true
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With