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()
}
}
Related
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()
}
}
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)
}
}
I am receiving notification from firebase, it navigates correctly if receive it on foreground or background. But if I tap on notification from blocking screen it does not work. I think the problem is from not finding navController. But don't know what to do
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.MainTheme)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
mainviewModel.navigateToMainFragmentEvent.observe(this, EventObserver {
Log.d("A","notification")`
Navigation.findNavController(this, R.id.nav_host_fragment)
.navigate(R.id.action_global_mainFragment)
})
}
}
SplashFragment is a homeFragment
class SplashFragment : Fragment(R.layout.activity_splash) {
val splashViewModel: SplashViewModel by sharedViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
getStringExtra(NOTIFICATION_TYPE)?.let {
splashViewModel.notificationRecived(it)
}
}
}
when I debug this code:
Navigation.findNavController(this, R.id.nav_host_fragment)
IllegalStateException: ID does not reference a View inside this Activity
My bottom navigation view with Navigation Component is recreating my fragments each time I navigate. I would like a Singletop, how can I do this?
I followed this tutorial: https://proandroiddev.com/android-navigation-arch-component-a-curious-investigation-3e56e24126e1
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupNavigation()
}
private fun setupNavigation() {
val navController = findNavController(R.id.mainNavigationFragment)
setupActionBarWithNavController(navController)
bottomNavigationView.setupWithNavController(navController)
}
override fun onSupportNavigateUp() =
findNavController(R.id.mainNavigationFragment).navigateUp()
}