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()
}
}
Related
I'm learning android development, Im looking up information about navigation components and fragments but I havent understood what is the diferent between
NavigationUI.setupActionBarWithNavController(this,navHostFragment.navController) and setupActionBarWithNavController(navController,appBarConfig).
bellow you can find two codes, In one Im using NavigationUI but In the other I dont.
First one:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding= ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
NavigationUI.setupActionBarWithNavController(this,navHostFragment.navController)
binding.bnNavBar.setupWithNavController(navHostFragment.navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.nav_host_fragment)
return navController.navigateUp()
}
}
Second one:
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var mainBinding: ActivityMainBinding
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(mainBinding.root)
val toolBar = mainBinding.activityMainContent.mainToolbar
//Setting up the tool bar as the app bar for the activity
setSupportActionBar(toolBar)
val host: NavHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment_container) as NavHostFragment
val navController = host.navController
//appBarConfiguration = AppBarConfiguration(navController.graph)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.continentFragment),
mainBinding.drawerLayout
)
//First
setUpActionBar(navController,appBarConfiguration)
//Second
setUpNavigationView(navController)
}
private fun setUpActionBar(navController: NavController, appBarConfig : AppBarConfiguration) {
setupActionBarWithNavController(navController,appBarConfig)
}
private fun setUpNavigationView(controller: NavController) {
mainBinding.navView.setupWithNavController(controller)
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
mainBinding.drawerLayout.closeDrawer(GravityCompat.START)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_container)
return navController.navigateUp(appBarConfiguration)|| super.onSupportNavigateUp()
}
override fun onBackPressed() {
if (mainBinding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
mainBinding.drawerLayout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
}
Please, I'd be very thankful if someone can explain me the diference.
Ive read a lot about navigation but I havent found anything useful
I want to load all fragment once or on first click. I don't want to recreate fragment on clicking bottom menu
MainActivity.kt
#AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var navController:NavController
private lateinit var appBarConfiguration:AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
supportActionBar?.hide()
val navView: BottomNavigationView = binding.navView
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment
navController = navHostFragment.navController
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_campaigns, R.id.navigation_credits,R.id.navigation_masks,R.id.navigation_messages
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController, appBarConfiguration)
}
}
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
I want to show navigation drawer icon instead of Back button on a certain fragment. I created the App with Navigation graph.
Let's say i have 2 fragments (LoginFragment and DashboardFragment) and one activity (MainActivity)
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
drawerLayout = binding.drawerLayout
val navController = this.findNavController(R.id.myNavHostFragment)
// prevent nav gesture if not on start destination
navController.addOnDestinationChangedListener { nc: NavController, nd: NavDestination, args: Bundle? ->
if (nd.id == nc.graph.startDestination) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
} else {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
}
}
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
NavigationUI.setupWithNavController(binding.navView, navController)
}
// Set up the back button on action bar
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return NavigationUI.navigateUp(navController, drawerLayout)
}
}
LoginFragment.kt
class LoginFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding:FragmentLoginBinding = DataBindingUtil.inflate(inflater,
R.layout.fragment_login, container, false)
// Hide the Action bar
(activity as AppCompatActivity).supportActionBar?.hide()
binding.loginButton.setOnClickListener {
//Some unimportant validation
}
return binding.root
}
}
DashboardFragment.kt
class DashboardFragment : Fragment() {
lateinit var binding : FragmentDashboardBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Binding object for this fragment and the layout
binding = DataBindingUtil.inflate(inflater,
R.layout.fragment_dashboard, container, false)
//Navigate to Product stock fragment when clicked
binding.productStockButton.setOnClickListener(Navigation.createNavigateOnClickListener(
R.id.action_dashboardFragment_to_productStockOutletList
))
//Navigate to Switching History fragment when clicked
binding.switchingHistoryButton.setOnClickListener(Navigation.createNavigateOnClickListener(
R.id.action_dashboardFragment_to_switchingHistoryFragment
))
//Navigate to Outlet List fragment for Outstanding Product when clicked
binding.outstandingOrderButton.setOnClickListener(Navigation.createNavigateOnClickListener(
R.id.action_dashboardFragment_to_outletListFragment
))
// Set action bar title to "Main Dashboard"
(activity as AppCompatActivity).supportActionBar?.title = "Main Dashboard"
// Declare that this fragment has menu
setHasOptionsMenu(true)
(activity as AppCompatActivity).supportActionBar?.show()
(activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(false)
//Return.... i don't know.
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater?.inflate(R.menu.nav_overflow_menu, menu)
}
}
And this is my Navigation graph (I set up LoginFragment as home)
I want to show the navigation drawer in the DashboardFragment instead of LoginFragment. (With LoginFragment still be the start of the graph). I already hide the Up button of the DashboardFragment
This is the current look of the dashboard. As you can see that the back button is already gone.
Is there anything i can do with it ? If there is something unclear let me know.
try this I hope that it will help you, this will hide actionBar on LoginFragment as it's the startDestination on graph and show it otherwise
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// prevent nav gesture if not on start destination
navController.addOnDestinationChangedListener { nc: NavController, nd: NavDestination, args: Bundle? ->
if (nd.id == nc.graph.startDestination) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
supportActionBar?.hide()
} else {
supportActionBar?.show()
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
}
}
// here this ids are form fragment which should show navigation icon
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_home,R.id.nav_gallery, R.id.nav_slideshow), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
I'm new to android and working through some tutorials. Currently working on implementing the Navigation controller and overriding the up button functionality. Part of doing this is to link the action bar with the Nav controller and overriding onSupportNavigateUp(). In doing this I noticed that we have to fetch the Nav Controller by id twice so I decided to create a class variable that does this and re-use the variable. The problem is the App crashes on startup when I do this. My guess is this is because I'm trying to get the Nav Controller before inflating the views?
So my question is why does this work:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
#Suppress("UNUSED_VARIABLE")
val binding = 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()
}
}
But this doesn't work:
class MainActivity : AppCompatActivity() {
private val navController = this.findNavController(R.id.myNavHostFragment)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
#Suppress("UNUSED_VARIABLE")
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp()
}
}
You are right, you are assigning the navController before the view is inflated and passed the null to setupActionBarWithNavController
You can do it like this,
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
#Suppress("UNUSED_VARIABLE")
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
NavigationUI.setupActionBarWithNavController(this, navController)
navController = this.findNavController(R.id.myNavHostFragment)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp()
}
}