How to handle deeplink by URI in Navigation graph Android? - android

How to open a deeplink using a CTA Uri in navigation components without losing backstack?
Motivation:
private fun openDeepLink(cta: String) { // cta= schema://host
navigationController?.run{
val deeplink = this
.createDeepLink()
.setDestination(cta)
.build()
handleDeepLink(deeplink)
}
}
or
navigationController?.createDeepLink()
?.setUriDestination(cta)
?.createTaskStackBuilder()
?.startActivities()
Using
navigationController?.handleDeepLink(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
just works with Up button (toolbar) and not with the system back button. I still can't understand why toolbar and native back are not aligned when I use:
toolbar.setupWithNavController(findNavController(R.id.activity_base_container))
and documentation says:
#param toolbar The Toolbar that should be kept in sync with changes
to the NavController.
With this I understand that toolbar will assume any changes of navController (changes on startDestination, open deeplinks etc)

Related

Problem with android toolbar using navigation drawer

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.

Navigation Controller (Managing Backstack) Jetpack Android

Good day. So I've been working around with NavComponent of Jetpack for Android
I've thought that management of BackStack of fragments had to be implemented there already, well in fact it is there but I have faced an issue.
Here is my structure:
I have and entry Activity
I have a NavHost in the activity
I have Bottom Navigation bar in the Activity
For each Bottom Item I am using separate Fragments to navigate through.
Here is the code for the navigation.
bottomNavigationView.setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.navigation_home -> {
navController.apply {
navigate(R.id.navigation_home)
}
true
}
R.id.navigation_dashboard -> {
navController.apply {
navigate(R.id.dashboardFragment)
}
true
}
R.id.navigation_notifications -> {
true
}
else -> {
false
}
}
}
Never mind the last item.
So the issue is next.
If I try to switch between home and dashboard multiple times, when I press back then the stack surely will start popping all the items included there. So if I move like 6 times it will take me 12 attempts to actually exit the app.
Currently I couldn't find any source where for example the navigate() method will accept some sort of argument to cash my fragments instead of recreating it each time and adding to the BackStack.
So what kind of approach would you suggest?
If I to manage the BackStack manually on each back button pressed, what's the purpose of NavController at all? Just for creating and FORWARD navigation?
I think I'm missing some source in Android's official docs.
Thank you beforehand.
P.S.
using navController.popBackStack() before calling navigate() surely isn't the correct choice.
According to the documentation here :
NavigationUI can also handle bottom navigation. When a user selects a menu item, the NavController calls onNavDestinationSelected() and automatically updates the selected item in the bottom navigation bar.
to do so you have to give your bottom navigation items an ids as same as the corresponding destination in your navigation graph , and then tie you bottom view to the controller like this :
NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
NavController navController = navHostFragment.getNavController();
BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
NavigationUI.setupWithNavController(bottomNav, navController);
Note : from my personal experience , when the startDestination in the graph , that start by default is not currently in back stack (In my case it was the landing page which i pop it out when going to home fragment) then the app act with weird behavior like this . so make sure the start destination is existed in your back stack on should work fine .

Is there a way to define the starting tab in the navigation advanced sample?

I am working on the project NavigationAdvancedSample of the
architecture-components-samples repository. This project shows a workaround to support multiple back stacks for each tab of a BottomNavigationView.
In this configuration, you define a navigation graph for each of your tabs and let the class extension NavigationExtensions handle the different back stacks for you. Everything works fine, but I can't find a way to select the starting tab of the BottomNavigationView. I have tried to tweak the NavigationExtensions but without success.
By default, the selected tab on the application startup is the first of the bottom navigation view. How can I change this behavior in order to show the second or third tab for example?
Changing order of items in the navGraphIds and selecting item in bottomNavigationView helped me.
private fun setupBottomNavigationBar() {
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
val navGraphIds = listOf(R.navigation.list, R.navigation.home, R.navigation.form)
bottomNavigationView.selectedItemId = R.id.list
// Setup the bottom navigation view with a list of navigation graphs
val controller = bottomNavigationView.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.nav_host_container,
intent = intent
)
// Whenever the selected controller changes, setup the action bar.
controller.observe(this, Observer { navController ->
setupActionBarWithNavController(navController)
})
currentNavController = controller
}
As a result I have R.id.list item as first.

Login - Navigation Architecture Component

I implemented conditional navigation to my LoginFragment, with android navigation architecture component. The problem I facing now, is that I would like to hide the up button on the toolbar, and the disable any in-app navigation while the user is not logged in.
I would like to be able to implement this with a one-activity approach, where the Activity sets up the in app navigation UI and the navController like in the android sunflower demo, and the navigation destinations are Fragments.
I implemented the conditional navigation as discribed here:
Navigation Architecture Component - Login screen
How can I properly implement hiding the navigation and the up button on the login screen, with Navigation Architecture Component?
I don't know exactly what you mean by hiding navigation, but I will assume you mean hiding a drawer layout. To hide the up button and lock the drawer add the following to your MainActivity's onCreate. I'm using Kotlin.
myNavController.addOnDestinationChangedListener { _, destination ->
if (destination.id == R.id.loginFragment) {
myDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
myToolbar.setVisibility(View.GONE)
} else {
myDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
myToolbar.setVisibility(View.VISIBLE)
}
To make just the up button go away use myToolbar.setNavigationIcon(null) and to make it come back use myToolbar.setNavigationIcon(R.id.my_icon)
My method is adding the login page to the root set
val navController = findNavController(R.id.main_nav_host)
val appBarConfiguration = AppBarConfiguration(setOf(R.id.home_dest,
R.id.user_dest,R.id.login_dest))
toolbar.setupWithNavController(navController, appBarConfiguration)
So when you are on the login page, there is no back button.
System back button can override onBackPressed()
override fun onBackPressed() {
if (findNavController(R.id.main_nav_host).currentDestination?.id != R.id.next_dest)
super.onBackPressed()
}
}
Sorry for my English

Navigation Architecture Component - Navigation Drawer

I am using Navigation Component with Navigation Drawer.
I have added Fragments for each Navigation item in the menu.
Add NavHostFragment where this Fragment will be swapped
Then added Fragments as Destinations
I want master Detail Navigation i.e.
start destination -> fragment 2
back button -> start destination
start destination -> fragment 2 -> fragment 3 -> fragment 4
back button -> start destination
My question is whether I should add any connections to this graph?
I also need to have one menu item which is just logout function call not fragment swapping, so I could not configure it with default setup
val navController = findNavController(R.id.main_nav_host_fragment)
nav_view.setupWithNavController(navController)
But rather have to use
nav_view.setNavigationItemSelectedListener(this)
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.navSignOut -> {
loginViewModel.logout()
}
else -> {
val navController = findNavController(R.id.main_nav_host_fragment)
navController.navigate(item.itemId)
}
}
drawer_layout.closeDrawer(GravityCompat.END)
return true
}
I also need to show Login Activity above (modally) the Main App Activity with Navigation Drawer. Can I use Navigation Graph for it and how?
Login Activity should: on back button -> close app, if logged out -> start above main activity, if logged in go to main activity
So I have to questions:
1. Should I use any actions?
2. Should I use custom navigation for drawer or setupWithNavController()?
3. What about modal login activity navigation?
The part I undrestood from your question is how to navigate to logout.
Usually when the user clicks on logout you want to log them out and navigate to a startup screen.
So you need to add your startup activity to nav_graph.
Michael, navigation architecture it is not that easy to understand at the beginning, what you want to is not the exception. But as this navigation is new, I just suggest you to follow the code lab.
https://codelabs.developers.google.com/codelabs/android-navigation/#0
I see for instance your line to close the drawer. The code lab has instructions on how to setup the nav drawer with navigation and the UI
I hope it helps you.

Categories

Resources