Is it really necessary to call
override fun onSupportNavigateUp() = findNavController(R.id.nav_host_fragment).navigateUp()
in my MainActivity ?
Because when I attach the NavHostFragment in my xml it starts from there, but I have seen the Google I/O lecture where they use it to make the start point of the navigation
My question
Where is it necessary to use it ?
Thanks
onSupportNavigateUp comes from AppCompatActivity. You should override the method in the same activity where you define your NavHostFragment (probably your MainActivity). You override it so that the NavigationUI can correctly support the up navigation or even the drawer layout menu. AppCompatActivity and NavigationUI are two indepenent components, so you override the method in order to connect the two. Note that if you set a toolbar with the navigation component, i.e., if you do something similar to
override fun onCreate(savedInstanceState: Bundle?) {
setContentView(R.layout.activity_main)
// ...
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(navController.graph)
findViewById<Toolbar>(R.id.toolbar).setupWithNavController(navController, appBarConfiguration)
}
you don't need to override the onSupportNavigationUp method as Navigation will automatically handle the click events.
You also don't need to override it if you want to handle the toolbar yourself.
Related
List the item
I'm developing an app using a navigation drawer and navigation components and I'm facing two issues:
I settled specifically each toolbar title where it is supposed to be, but every time I change the fragments, in the toolbar, for an instant, I can see the previous name from the fragment, which is the fragment name itself. So, it quickly changes from MySpecificFragment to MyFragmentName and I would like it to not happen. I've settled the title even onCreateView or onViewCreated. It didn't matter, still happening.
How could I decide the direction in which the back button of the fragment goes? I would like to create a standard position where the back button arrow goes, always the same. But it just travels back to the previous fragment (which is not a real problem, but I would like to improve its behavior)
Sorry for the lack of code, I don't know what I am supposed to display since I'm going against the standard android behavior.
P.S.: Using android studio and kotlin
Regarding the first issue, one way to avoid the brief display of the previous fragment name in the toolbar is to set the toolbar title in the parent activity and then update it from the fragment's onResume() method. This ensures that the toolbar title is set correctly when the fragment is resumed after being pushed onto the back stack. Here's an example code snippet:
In your activity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
}
fun setToolbarTitle(title: String) {
supportActionBar?.title = title
}
}
In your fragment:
class MySpecificFragment : Fragment() {
override fun onResume() {
super.onResume()
(activity as? MainActivity)?.setToolbarTitle("MySpecificFragment")
}
}
Regarding the second issue, you can customize the back button behavior by using a custom NavController.OnDestinationChangedListener. In the listener, you can set the back button icon and its behavior based on the current and previous destinations. Here's an example code snippet:
class MyNavigationController(activity: AppCompatActivity, navController: NavController) {
init {
navController.addOnDestinationChangedListener(
activity, object : NavController.OnDestinationChangedListener {
override fun onDestinationChanged(
controller: NavController,
destination: NavDestination,
arguments: Bundle?
) {
if (destination.id == R.id.my_fragment) {
activity.supportActionBar?.setDisplayHomeAsUpEnabled(false)
} else {
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)
activity.supportActionBar?.setHomeActionContentDescription(R.string.back)
activity.supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)
activity.supportActionBar?.setDisplayShowHomeEnabled(true)
}
}
})
}
}
Here, you can adjust the back button icon and behavior based on the current and previous destinations by setting setDisplayHomeAsUpEnabled, setHomeAsUpIndicator, and setHomeActionContentDescription.
Edit:
The original question was Is there a way to get a reference to a fragment that is displayed using a BottomNavigationView?. But I've figured some things out and realized I was asking the wrong question.
I'd like to get a reference to a fragment that is being displayed using a BottomNavigationView.
This is how my BottomNavigationView is being setup. It's in onCreate of an Activity.
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.bottom_nav_view_nav_host)
val appBarConfiguration = AppBarConfiguration(setOf(
R.id.navigation_first_list,
R.id.navigation_second
))
setupActionBarWithNavController(navController, appBarConfiguration)
bottomNav.setupWithNavController(navController)
I've tried to get the fragment with bottomNav.findFragment<TheFragmentType>() it throws an exception.
I was asking the wrong question originally. I can just use the navController to call the correct navigation component in order to show the right fragment with a back stack.
val bundle = bundleOf("someId" to "theId")
navController.navigate(R.id.action_navigation_list_to_details, bundle)
What I'm trying to do
I am using Android Navigation component to handle navigation in my app. In this example, I have two screens, screen A and screen B.
I want the user to be able to click a button in screen A and be able to navigate to screen B; and then be prevented from going back to the previous screen (screen A).
The problem
When the user navigates to screen B from screen A, the back button on the action bar still allows the user to go back to the previous screen, however when clicking on the back button in the bottom bar it exits the app so this part works OK.
What do I need to do in order to remove the back button in the Action Bar?
What I've read so far
I have followed the guidance within these three articles but I think they might be ignoring the ActionBar's back button:
Stackoverflow - How to clear navigation Stack after navigating to
another fragment in Android
Android Developer Guide - Conditional navigation
Android Developer Guide - Navigate to a destination
My Code
Navigation Graph - nav_graph.xml
<?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"
android:id="#+id/nav_graph"
app:startDestination="#id/screen_a">
<fragment
android:id="#+id/screen_a"
android:name="com.example.conditionalnavigation.AFragment"
android:label="screen A">
<action
android:id="#+id/action_AFragment_to_BFragment"
app:destination="#id/screen_b"
app:launchSingleTop="true"
app:popUpTo="#id/screen_a"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="#+id/screen_b"
android:name="com.example.conditionalnavigation.BFragment"
android:label="screen B" />
</navigation>
MainActivity - This acts as my Single Activity navhost.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
val navController = this.findNavController(R.id.myNavHostFragment)
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return navController.navigateUp()
}
}
In your activity class add the following member (in Kotlin):
private lateinit var appBarConfiguration: AppBarConfiguration
Inside the onCreate method add the following lines:
....
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
...
...
appBarConfiguration = AppBarConfiguration(
setOf([**ID of the fragment layout you want without back button**],
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
....
In this way your fragment will be a root fragment and the back button is removed. Hope it helps.
Try to disable home button at the creation of screen b fragment:
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
var rootView = inflater?.inflate(R.layout.fragment_screen_b, container, false)
(activity as AppCompatActivity).supportActionBar!!.setDisplayHomeAsUpEnabled(false)
return rootView
}
If it didn't work, then try it in onViewCreated() method.
If not worked, try to add below as well:
setHasOptionsMenu(false)
I've used the default bottom navigation template in Android Studio. This has been working fine so far. However, I'd like to change one of the buttons to a button which triggers a camera intent. I'm not sure how to do this since I assume the default implementation uses built-in functions which I can't change.
I believe setupWithNavController is responsible for navigating to the matching fragment. Is there any way to change this, so that I add a button that launches the camera?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
navView.setupWithNavController(navController)
}
}
Remove setupWithNavController and create your own menu.xml file. Then you can use your menu with adding like this:
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/main" />
After that, you can implement setOnNavigationItemSelectedListener on your NavigationBar inside Kotlin class.
I am using Android architecture components with the Single Activity pattern on Android. The navigation pattern I am using is BottomNavigationView.I actually want the parent activity to have no ActionBar but setting my theme to be of type NoActionBar crashes the App. Setting Navigation in Activity has been done as below
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.navigation_popular, R.id.navigation_top_rated, R.id.navigation_favorites)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
How do I set up bottom navigation to have no actionBar since I wish to have on of the some fragments with ActionBar, like CollapsingToolbarLayout?
I think you found the solution but for the others,
if you want to use the BottomNavigationView with the .NoActionBar theme so you should remove these lines:
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.navigation_popular, R.id.navigation_top_rated, R.id.navigation_favorites)
)
setupActionBarWithNavController(navController, appBarConfiguration)
Using Android Navigation BottomNavigationView. Do not restrict activity with NoActionBar in manifest. Instead from your activity retrieve an instance of your support action bar and use its public method hide()
if (savedInstanceState == null) {
setupBottomNavigationBar()
} // Else, need to wait for onRestoreInstanceState
supportActionBar?.hide()