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
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'am want to save fragment with google map when i navigate by using bottom navigation bar, but if go to fragment A (for example) and back to MapFragment, in backstack will be added new MapFragment and it wiil make new request to google map api, that wasting time. i save the bundle but it's not what i want. How can i create one MapFragment and using it or maybe i should use other way?
#AndroidEntryPoint
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)
val navHostFragment = supportFragmentManager.findFragmentById(
R.id.navHostFragment
) as NavHostFragment
navController = navHostFragment.navController
// Setup the bottom navigation view with navController
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
bottomNavigationView.setupWithNavController(navController)
appBarConfiguration = AppBarConfiguration(
setOf(R.id.mapFragment, R.id.eventsFragment, R.id.profileFragment)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navController.addOnDestinationChangedListener { _, destination, _ ->
}
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration)
}
}
#AndroidEntryPoint
class MapFragment : Fragment(R.layout.fragment_map) {
private var hasMapConfigured: Boolean = false
private lateinit var persistedMapBundle: Bundle
companion object {
private const val MAP_VIEW_BUNDLE_KEY = "mapview_bundle_key"
}
private val callback = OnMapReadyCallback { googleMap ->
val sydney = LatLng(-34.0, 151.0)
googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
persistedMapBundle = savedInstanceState?.getBundle(MAP_VIEW_BUNDLE_KEY) ?: Bundle()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mapViewBundle = savedInstanceState?.getBundle(MAP_VIEW_BUNDLE_KEY)
initMapViewState(mapView, mapViewBundle)
mapView.getMapAsync(callback)
}
override fun onResume() {
super.onResume()
mapView?.onResume()
}
override fun onStart() {
super.onStart()
mapView?.onStart()
}
override fun onStop() {
super.onStop()
mapView?.onStop()
}
override fun onPause() {
super.onPause()
mapView?.onPause()
}
override fun onLowMemory() {
super.onLowMemory()
mapView?.onLowMemory()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelable(MAP_VIEW_BUNDLE_KEY, persistedMapBundle)
outState.putBundle(MAP_VIEW_BUNDLE_KEY, persistedMapBundle)
}
override fun onDestroyView() {
super.onDestroyView()
mapView.onSaveInstanceState(persistedMapBundle)
mapView.onDestroy()
}
private fun initMapViewState(mapView: MapView, savedMapViewBundle: Bundle?) {
if (!persistedMapBundle.isEmpty) {
mapView.onCreate(persistedMapBundle)
hasMapConfigured = true
return
}
mapView.onCreate(savedMapViewBundle)
hasMapConfigured = savedMapViewBundle != null
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="SpeakableTextPresentCheck,SpeakableTextPresentCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
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)
}
}
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()
}
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()
}
}