Jump between two navigation graphs - android

For navigation, I use the Navigation The component I connected to it using the Navigation Extension BottomNavigationView. I tried to switch from one graph to another, but he always showed me an error that he could not find a path where to go. If the way to go from one graph to another
the code where the Navigation Component and bottomNavView are connected
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var appBarConfiguration: AppBarConfiguration
private var currentNavController: LiveData<NavController>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
if (savedInstanceState == null) {
initNavigationComponent()
}
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
initNavigationComponent()
}
override fun onSupportNavigateUp(): Boolean {
return currentNavController?.value?.navigateUp(appBarConfiguration) ?: false
|| super.onSupportNavigateUp()
}
private fun initNavigationComponent() {
appBarConfiguration =
AppBarConfiguration(setOf(R.id.auth_fragment, R.id.main_screen_fragment))
setSupportActionBar(toolbar)
val navGraphIds =
listOf(R.navigation.nav_main, R.navigation.nav_catalog, R.navigation.nav_profile)
// Setup the bottom navigation view with a list of navigation graphs
val controller = bottom_nav.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.main_nav_fragment,
intent = intent
)
controller.observe(this, { navController ->
setupActionBarWithNavController(navController,appBarConfiguration)
collapsingToolbarLayout.setupWithNavController(
toolbar,
navController,
appBarConfiguration
)
navController.addOnDestinationChangedListener {...} )
currentNavController = controller
}
}
Tried connecting with <include app:graph = "#navigation/myGraph" /> but that doesn't work either

for multi backstack navigation between BottomNavigationView tabs use this sample of google:
Multiple BackStack Navigation

Related

Cannot hide back button on action bar

My application have two top level fragment A and B controlled by a bottom navigation bar and fragment C can be navigated only from fragment B. I don't want the action bar on fragment C shows back button while it cannot be hidden by setDisplayShowHomeEnabled() or setDisplayHomeAsUpEnabled()
How can I hide the back button?
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navController = findNavController(R.id.navHostFragment)
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.aFragment, R.id.bFragment)
)
setupActionBarWithNavController(navController, appBarConfiguration)
binding.navView.setupWithNavController(navController)
}
}
Try to set home fragment destination
var navHostFragment = supportFragmentManager
.findFragmentById(R.id.container) as NavHostFragment
var mNavController = navHostFragment.findNavController()
override fun onSupportNavigateUp(): Boolean {
return when (mNavController.currentDestination?.id) {
R.id.homeFrg -> {
true
}
else -> mNavController.navigateUp()
}
}

How to create a dialog in the Fragment from the Activity using the Navigation component

I want to create a dialog in the Fragment directly from the Activity using the Navigation component.
The only solution I have found is this below.
Anyone have a better solution?
In Activity:
private lateinit var navHostFragment: NavHostFragment
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment_content_main) as NavHostFragment
navController = navHostFragment.navController
}
private fun openDialogAbout() {
val finestraDialogo = Dialog(navHostFragment.requireContext())
finestraDialogo.window
finestraDialogo.requestWindowFeature(Window.FEATURE_NO_TITLE)
finestraDialogo.setContentView(R.layout.dialog_about)
finestraDialogo.setCancelable(true)
finestraDialogo.show()
val window: Window? = finestraDialogo.window
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
You can call it from the Fragment with some modifications.
private fun openDialogAbout() {
val finestraDialogo = Dialog(requireActivity())
finestraDialogo.window
finestraDialogo.requestWindowFeature(Window.FEATURE_NO_TITLE)
finestraDialogo.setContentView(R.layout.dialog_about)
finestraDialogo.setCancelable(true)
finestraDialogo.show()
val window: Window? = finestraDialogo.window
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}

how to perform an action instead of moving to another destination if I click a menu in Navigation Drawer using Navigation Component?

I am trying to use Jetpack Navigation component. so navigation component will automatically handle if I want to segue from a destination to another destination when I click a menu in the navigation drawer
but I want to perform an action if a menu is clicked, say for example if a menu in drawer is clicked then I want to show a toast message.
in old way, ie using fragment transaction, I can easily check from onNavigationItemSelected, but I am no longer find that method
so how to do that in navigation component ?
I have tried to check onDestinationChanged , but it doesn't work
override fun onDestinationChanged(controller: NavController, destination: NavDestination, arguments: Bundle?) {
if (destination.id == R.id.my_destination {
// show toast in here
// but it doesn't work
}
}
here is my MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var navController : NavController
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
appBarConfiguration = AppBarConfiguration(setOf(
R.id.destination_share,
R.id.destination_message,
R.id.destination_chat),
drawer_layout
)
// init nav controller
navController = Navigation.findNavController(this,R.id.nav_host_fragment)
// set toolbar
setSupportActionBar(toolbar)
// set up navigation drawer
NavigationUI.setupActionBarWithNavController(this,navController, appBarConfiguration)
NavigationUI.setupWithNavController(navigation_view,navController)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController,appBarConfiguration)
}
}
You can handle Menu clicks as following
navView.menu.findItem(R.id.logout)
.setOnMenuItemClickListener { menuItem: MenuItem? ->
// write your code here
true
}
Have you tried using
bottom_nav_view.setOnNavigationItemSelectedListener {
if (destination.id == R.id.my_destination {
// show toast in here
// but it doesn't work
}
}

Move to MainActivity with Jetpack Navigation

How i can move from SettingsListFragment in my MainActivity?
<fragment
android:id="#+id/settings_list_fragment"
android:name="com.mandarine.targetList.features.settings.SettingsListFragment"
android:label="#string/settings"
tools:layout="#layout/fragment_settings_list">
</fragment>
Because in my navigation graph i haven't screen from MainActivity.
Whole navigation i have in my one activity, u can check code
class MainActivity : AppCompatActivity(), MainActivityViewContract {
private lateinit var auth: FirebaseAuth
private lateinit var mAuthStateListener: FirebaseAuth.AuthStateListener
private val presenter = MainActivityPresenter(contract = this)
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
signIn()
setupViews()
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.nav_host_fragment).navigateUp(appBarConfiguration)
}
override fun onResume() {
super.onResume()
auth.addAuthStateListener(mAuthStateListener)
}
override fun onPause() {
super.onPause()
auth.removeAuthStateListener(mAuthStateListener)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
presenter.onActivityResult(requestCode, resultCode)
}
override fun cancelSignIn() {
finish()
}
private fun setupViews() {
val host: NavHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: return
val navController = host.navController
appBarConfiguration = AppBarConfiguration(navController.graph)
val drawerLayout: DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.target_list, R.id.settings_list_fragment, R.id.calendar_fragment),
drawerLayout
)
setupActionBar(navController, appBarConfiguration)
setupNavigationMenu(navController)
setupBottomNavMenu(navController)
}
private fun setupNavigationMenu(navController: NavController) {
val sideNavView = findViewById<NavigationView>(R.id.nav_view)
sideNavView?.setupWithNavController(navController)
}
private fun setupActionBar(
navController: NavController,
appBarConfig: AppBarConfiguration
) {
setupActionBarWithNavController(navController, appBarConfig)
}
private fun setupBottomNavMenu(navController: NavController) {
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_navigation_view)
bottomNavigationView?.setupWithNavController(navController)
}
private fun signIn() {
auth = FirebaseAuth.getInstance()
mAuthStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
presenter.signIn(activity = this, user = firebaseAuth.currentUser)
}
}
}
You can add an <activity../> tag in your navigation graph and set it as destination in actions.
<activity
android:id="#+id/main_activity_destination"
android:name="com.mandarine.your.package.path.here.MainActivity" />
Then, you can call navController.navigate(R.id.main_activity_destination)
Or, if you want more control over the flow from the nav graph, you can create an action:
<action
android:id="#+id/go_to_main_activity"
app:clearTask="true"
app:destination="#+id/main_activity_destination"
app:launchSingleTop="true"
app:popUpTo="#id/main_activity_destination" />
Then, you can call navController.navigate(R.id.go_to_main_activity)
The question is not completely clear, but it seems like what you are trying to achieve is fragment navigation using NavController. Before answering the question, let me give you a brief understanding of how the new jetpack navigation works.
You will be having a single activity in your application(can have multiple activities as well, but for the sake of explaining, I am sticking with one). In this particular activity, you are having a single NavigationHostFragment, which is responsible for all your app navigation. This NavigationHostFragment will be equivalent to the container for adding Fragments in older way of doing it. The NavigationHostFragment will have a navigation controller, which will be linked to the storyboard. The navigation.xml file which you referred in the question is your storyboard.
The storyboard will contain all the fragments which you need in the navigation and the navigation directions as well. The navigation directions is referred to as actions. Each action in a fragment will be a navigation to a separate fragment.
Hence the navigation has nothing to do with Activity, it is all happening in the NavigationHostFragment(which I hope you already have in place in your Activity's xml file).
With these fundamentals, with two fragments, in which FragmentA is navigating to FragmentB, your navigation xml file will look somewhat like this:
<fragment android:id="#+id/fragmentA" android:name="com.xxx.xxx.FragmentA"
android:label="fragment_a" tools:layout="#layout/fragment_a">
<action android:id="#+id/action_fragmentA_to_fragmentB"
app:destination="#id/fragmentB"/>
</fragment>
<fragment android:id="#+id/fragmentB"
android:name="com.xxx.xxx.FragmentB"
android:label="fragment_b" tools:layout="#layout/fragment_b">
</fragment>
And then in FragmentA code, where you need to perform the navigation, just call:
findNavController().navigate(R.id.action_fragmentA_to_fragmentB)

How to listen to Fragment Change in Navigation Component?

How can I add Fragment Change Listener in new Navigation Component?
I have a BottomNavigationView in which I used new Navigation Component following official sample
I have four destinations in my BottomNavigationView, all of them have their navigation graphs.
val navGraphIds = listOf(R.navigation.nav_home, R.navigation.nav_discover, R.navigation.nav_search, R.navigation.nav_my)
val controller = bottom_nav.setupWithNavController(
navGraphIds = navGraphIds,
fragmentManager = supportFragmentManager,
containerId = R.id.navHostContainer,
intent = intent
)
controller.observe(this, Observer { navController ->
setupActionBarWithNavController(navController)
})
I want to have a listener in my MainActivity when fragment changed in any of 4 navigation graphs.
the controller is only affective when switching between BottomNavigationView destinations.
Have you tried NavController.OnDestinationChangedListener?
private lateinit var controller: NavController // don't forget to initialize
private val listener = NavController.OnDestinationChangedListener { controller, destination, arguments ->
// react on change
// you can check destination.id or destination.label and act based on that
}
override fun onResume() {
super.onResume()
controller.addOnDestinationChangedListener(listener)
}
override fun onPause() {
controller.removeOnDestinationChangedListener(listener)
super.onPause()
}
Addition to marat and vlad answers , if u use FragmentContainer in Xml , you can access it's nav controller by this :
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
else may encounter IllegalStateException of acitivity dont have navcontroller

Categories

Resources