I was following the official developer.android.com code labs when I encounter this issue
In the MainActivity, you should already have code to set up the app bar (also known as action bar) with the nav controller. Make navController a class variable so you can use it in another method.
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
}
Within the same class, add code to override the onSupportNavigateUp() function. This code will ask the navController to handle navigating up in the app. Otherwise, fall back to back to the superclass implementation (in AppCompatActivity) of handling the Up button.
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
Run the app. The Up button should now work from the FlavorFragment, PickupFragment, and SummaryFragment. As you navigate to previous steps in the order flow, the fragments should show the right flavor and pickup date from the view model.
This is my android studio error
Related
this my Auth Activity
class AuthActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityAuthBinding.inflate(layoutInflater)
setContentView(binding.root)
navController = Navigation.findNavController(this, fragment.id)
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController, null)
}
}
LoginFragment -> if login is success goto "AcceptCodeFragment"
viewModel.loginResponse.observe(viewLifecycleOwner, { response ->
viewBinding.pbLogin.visible(response is Resource.Loading)
when (response) {
is Resource.Success -> {
viewBinding.tvResponse.text = response.value.message
val action = LoginFragmentDirections.actionLoginFragmentToAcceptCodeFragment()
findNavController().navigate(action)
}
is Resource.Error -> if (response.isNetworkError) {
requireView().snackBar("Check your connection")
} else {
requireView().snackBar(response.errorBody.toString())
}
}
in AcceptCodeFragment Back button not work.
Two fragments using same viewmodel.
Your issue is not with the back button not working, it is that LiveData is for state, not events like your loginResponse. As LiveData is for events, it redelivers the previous response when you go back to your LoginFragment. This then triggers your navigate() call again, pushing you right back to your AcceptCodeFragment.
As per the LiveData with SnackBar, Navigation, and other events blog post, LiveData cannot be directly used for events. Instead, you should consider using an event wrapper or another solution (such as a Kotlin Flow) that allow your events to only be handled once.
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
}
}
I have an activity which holds FragmentContainerView. In the FragmentContainerView I have a NavHostFragment. I want to implement onSupportNavigateUp in the NavHostFragment.
class MenuNavHostFragment : Fragment() {
fun onSupportNavigateUp(): Boolean {
return NavigationUI.navigateUp(navController,null)
}
}
in MainActivity.kt
private lateinit var menuNavHostFragment: MenuNavHostFragment
override fun onSupportNavigateUp(): Boolean {
return menuNavHostFragment.onSupportNavigateUp()
}
in fragment_menu_nav_host
...
tools:context=".View.MenuNavHostFragment">
<fragment
android:id="#+id/fragment_menu_nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
...
When I press the back button, my application destroys when I want it to go back one step in the navigation stack.
How do I solve this?
check Update UI components with NavigationUI
If you want go back, use findNavController.navigateUp() function
replace the mentioned code by the following one, according to your program:
open fun navigateUp (drawerLayout: DrawerLayout, navController: NavController):Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return navigateUp(this.drawerLayout, navController)
}
I've searched my problem but I could not find anything. let me describe my problem.
I have 3 buttons on BottomNavigationView (Home, User, History). then from other activity, I have a button which I want is going to User page (with BottomnavigationView of course.
I will show you my code. it still defaults all. I just do not know how to navigate to the User page.
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_user, R.id.navigation_notifications
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}}
and here is my code (from other fragment)
otherFragment.kt
buttonRincian.setOnClickListener {
// i dont know command to go to MainActivity with User page as default selected menu
}
thank you so much, i hoe someone can help me.
Make an interface which your activity will implement.
All the fragments should call the method of the interface wherever you want to change the fragment.
something like
interface TabChangeListener {
fun onTabChange(tabName : String)
}
Code in Activity
class Activity : AppCompatActivity(), TabChangeListener {
override fun onTabChange(tabName : String) {
//code to show different tabs
}
}
Code in Fragments
class Frag1 : Fragment {
var listener : TabChangeListener
//somewhere in the code
listener.onTabChange("userTab")
}
Don't forget to take the reference of TabChangeListener in Fragments from the activity otherwise the callbacks won't work.
I am making a simple note taking app, I have 2 fragments with navigation component, one fragment has a list of notes and the other is for editing or creating a new note.
In MainActivity I added
val navController = this.findNavController(R.id.host_fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
and then override onSupportNavigateUp()
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.host_fragment)
return navController.navigateUp()
}
In NoteEditFragment
requireActivity().onBackPressedDispatcher.addCallback(this) {
saveOrUpdateNote(noteId, note)
}
now it all works well when pressing the "back button" in the device, However onBackPressedDispatcher.addCallback() is note triggered when I press the "up button" the one on the top left of the screen.
My question is : How do I handle this up button from my NoteEditFragment?
Thanks in advance
Finally, I found the solution.
First In the activity onCreate method I had to connect the navigation like I did:
val navController = this.findNavController(R.id.host_fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
Then still in MainActivity override onSupportNavigateUp() :
override fun onSupportNavigateUp(): Boolean
{
val navController = this.findNavController(R.id.host_fragment)
return navController.navigateUp()
}
Then In the Fragment onCreateView I had to enable option menu:
setHasOptionsMenu(true)
then in the fragment I overridden onOptionsItemSelected :
override fun onOptionsItemSelected(item: MenuItem): Boolean
{
// handle the up button here
return NavigationUI.onNavDestinationSelected(item!!,
view!!.findNavController())
|| super.onOptionsItemSelected(item)
}
Note: I think if you have more than one option menu, then I think you have to do a when (item) statement to check what option has been chosen.
Also if you want to handle the device back button then you can do like this in your fragment onCreateViewMethod :
requireActivity().onBackPressedDispatcher.addCallback(this)
{
// handle back button
// change this line to whatever way you chose to navigate back
findNavController().navigate(NoteEditFragmentDirections.actionNoteEditFragmentToNoteListFragment())
}
I think the accepted answer is a bit messy. So, i found a clean code. It is perfect for my use case as i don't need to do anything special when the device back button is pressed. Therefore, anyone here with the same requirements can follow my code.
In onCreate of MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(navController.graph)
// Check if androidx.navigation.ui.NavigationUI.setupActionBarWithNavController is imported
// By default title in actionbar is used from the fragment label in navigation graph
// To use the app name, remove label else if you want to add customized label specify it there
setupActionBarWithNavController(this, navController, appBarConfiguration)
...
}
Again, in the MainActivity itself:
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.fragment)
// Check if androidx.Navigation.ui navigateUp is imported and used
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
I have added comments for better understanding. If you think the answer is helpful then please upvote. Thank You. Happy Development :)
EDIT 1:
No need to use supportActionBar.setDisplayHomeAsUpEnabled(true) in the fragments. AppBarConfiguration will take care of it.
if you use noActionBar themes and you want to use your own toolbar as an actionBar for the fragment, you can use this method
in the host activity
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.navHostFragment).navigateUp()
}
in the onCreateView of the fragment
(activity as AppCompatActivity).setSupportActionBar(binding.toolbar)
(activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
in very simple way you just need to set the supportNavigateUp on the Activity.
in MainActivity:
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
setupActionBarWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
in my case its worked