Navigation Component with different Toolbars&Menus - android

I am working on app that uses Navigation pattern.
Now I have an Activity and few fragments.
Each Fragment has a unique functionality so I created a separate toolbar for each fragment: collapsing, usual or no toolbar at all.
I used the following example: https://android.jlelse.eu/instagram-style-navigation-using-navigation-component-854037cf1389
It works pretty well, but now I am taking an issue if I want to set some menu items in the toolbar.
For example, I would like to add a settings menu to the toolbar of the Profile Fragment
I tried setting a menu item, but it simply never appears and I think the method doesn't get called at all..
Is it possible to solve this issue without changing the whole architecture logic?
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.my_layout, container, false)
setHasOptionsMenu(true)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.toolbar.apply {
setupWithNavController(findNavController())
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.main_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == R.id.action_get_info)
Toast.makeText(context!!, "test message", Toast.LENGTH_SHORT).show()
return super.onOptionsItemSelected(item)
}
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_get_info"
android:icon="#drawable/ic_setting"
android:title="Settings"
app:showAsAction="always" />
</menu>
<layout 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"
tools:context="com.example.MyFragment">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
style="#style/ToolbarAppearance"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_test_image" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

Related

I don't see the options menu in the fragment

I am using bottom navigation. I want to open a dialog window by selecting the option menu after switching to another fragment screen through the bottom menu.
But I don't see the option menu..
I wrote it by referring to other sample code, but I do not know the cause
WorkoutListFragment.kt
class WorkoutListFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_workout_list, container,false)
return view
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.record_item_add, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val dialog = BodyPartDialogFragment()
dialog.show(activity!!.supportFragmentManager, "BodyPartDialog")
return true
}
}
ADDED
val toolbar: Toolbar = view.findViewById(R.id.toolbar)
(activity as AppCompatActivity).setSupportActionBar(toolbar)
WorkouListFragment.xml
<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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.WorkoutListFragment">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:theme="#style/Theme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="LIST"
app:titleTextColor="#color/black"
app:titleMarginStart="30dp"
android:paddingRight="30dp"
android:theme="#style/Theme.PopupOverlay"/>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Cannot set Toolbar menu with NavigationDrawer

I'm trying to combine NavigationDrawer with a Toolbar that has a refresh Menu option:
The problem I'm encountering is that I cannot make the Toolbar show the menu button.
My MainActivity only holds a Fragment. activity_main.xml:
<androidx.fragment.app.FragmentContainerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_nav_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/main" />
MainActivity.kt:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
nav_main:
<navigation 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"
android:id="#+id/nav_main"
app:startDestination="#id/drawerFragment"
>
<fragment
android:id="#+id/drawerFragment"
android:name="com.example.rocketman.drawer.DrawerFragment"
android:label="DrawerFragment"
tools:layout="#layout/fragment_drawer"
/>
</navigation>
Basically my MainActivity navigates directly into a DrawerFragment, which is here:
<androidx.drawerlayout.widget.DrawerLayout
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"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.rocketman.drawer.DrawerFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.rocketman.drawer.DrawerFragment">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/midnight_blue"
app:titleTextColor="#color/white"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/drawer_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/drawer_nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/drawer_header"
app:menu="#menu/drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
And finally, my DrawerFragment:
private const val KEY_SELECTED_DRAWER_ITEM = "DRAWER_SELECTED_ITEM_ID_KEY"
class DrawerFragment: Fragment() {
private lateinit var binding: FragmentDrawerBinding
private var drawerSelectedItemId = R.id.nav_home
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentDrawerBinding.inflate(inflater)
(requireActivity() as AppCompatActivity).setSupportActionBar(toolbar_home)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
savedInstanceState?.let {
drawerSelectedItemId = it.getInt(KEY_SELECTED_DRAWER_ITEM, drawerSelectedItemId)
}
setupDrawer()
setBackPressedHandler()
}
private fun setBackPressedHandler() {
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (binding.drawerLayout.isOpen) {
binding.drawerLayout.close()
} else {
findNavController().popBackStack()
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(KEY_SELECTED_DRAWER_ITEM, drawerSelectedItemId)
super.onSaveInstanceState(outState)
}
private fun setupDrawer() {
val controller = binding.drawerNavView.setupWithNavController(
childFragmentManager,
findNavController(),
listOf(
//all the items on the Drawer have their own navigation graph
R.navigation.home,
R.navigation.rocket,
R.navigation.company
),
R.id.drawer_container,
drawerSelectedItemId,
requireActivity().intent
)
controller.observe(
viewLifecycleOwner,
{ navController ->
NavigationUI.setupWithNavController(
binding.toolbarHome,
navController,
binding.drawerLayout
)
drawerSelectedItemId = navController.graph.id
}
)
}
}
In other words, the Drawer has three items: home, rocket and company as can be seen here, menu/drawer:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/nav_home"
android:checked="true"
android:checkable="true"
android:icon="#drawable/ic_home"
android:title="#string/nav_menu_home"
/>
<item
android:id="#+id/nav_rocket"
android:checkable="true"
android:icon="#drawable/ic_rocket"
android:title="#string/nav_menu_rocket_list"
/>
<item
android:id="#+id/nav_company"
android:checkable="true"
android:icon="#drawable/ic_company"
android:title="#string/nav_menu_company_data"
/>
</menu>
Each of home, rocket and company have their own navigation graph, for example navigation/company looks like this:
<navigation 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"
android:id="#+id/nav_company"
app:startDestination="#id/companyDataFragment">
<fragment
android:id="#+id/companyDataFragment"
android:name="com.example.rocketman.company.CompanyFragment"
android:label="#string/nav_menu_company_data"
tools:layout="#layout/fragment_company_data"
/>
</navigation>
And the CompanyFragment is straight forward:
class CompanyFragment: Fragment() {
private lateinit var binding: FragmentCompanyDataBinding
private val vm by lazy {
ViewModelProvider(this).get(CompanyVM::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
Repo.init(requireContext())
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentCompanyDataBinding.inflate(inflater)
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.company, menu)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupObservers()
}
private fun setupObservers() {
//observing
}
}
That part works.
However, I want to create a menu action for Company. So first I create a menu item menu/company:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/update"
android:icon="#drawable/ic_baseline_refresh_24"
android:title="#string/menu_company_update"
app:showAsAction="ifRoom|withText"
/>
</menu>
Then in CompanyFragment I call override onCreate() { setHasOptionsMenu(true) } and override onCreateOptionsMenu() { inflater.inflate(R.menu.company, menu }.
This should create the options menu for the Toolbar. However, the Fragment only shows the drawer menu icon but not the options menu icon.
I can add a Toolbar to the content Fragment itself but then the app has two Toolbars, the one with the drawer and the one with option items:
How do I make the Toolbar have both the NavigationDrawer and option items?
Still many people continue to use ActionBar, we don't have to use it any more. And if I were you, I would not use ActionBar and setHasOptionsMenu(true) which is related to ActionBar, but just would use a Toolbar.
Just delete setHasOptionsMenu(true), onCreateOptionsMenu() and onOptionsItemSelected() (if you have it).
Instead, use Toolbar.inflateMenu() and Toolbar.setOnMenuItemClickListener() directly on your Toolbar.
From what I understand from your question, you want to display overflow menu along with drawer menu.
The showAsAction option in the menu xml file is what you can use to control how that single menu option will show up in the actionbar.
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/update"
android:icon="#drawable/ic_baseline_refresh_24"
android:title="#string/menu_company_update"
app:showAsAction="ifRoom|withText"
/>
</menu>
change this to
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/update"
android:icon="#drawable/ic_baseline_refresh_24"
android:title="#string/menu_company_update"
app:showAsAction="never"
/>
</menu>
This will show the menu item in the Overflow menu.

Android: Navigation Component - How to connect Toolbar menu to the fragments?

Iv been stuck in trying to add the Navigation Component to my app. Specifically to my toolbar menu items.
I have been following the navigation migrate documentation on Android's site but I am getting a but confused on how it works or even to set it up.
This is a single-activity multi-fragment architecture.
The app would start in the MainFragment and then when tapping the menu items in the toolbar, such as Main Frag to Search Movie Frag. The user would be able to navigate using the menu items from anywhere in the app (e.g. if they click the home icon, they should be sent to the home screen form anywhere in the app. Still thinking if thats how it should be done).
The main thing is I don't know how to properly attach the Navigation Component to the menu items.
App
Nav Graph
nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
android:id="#+id/nav_graph"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="com.example.movieapp.ui.main.MainFragment"
android:label="MainFragment">
<action
android:id="#+id/action_mainFragment_to_searchMovieFragment"
app:destination="#id/searchMovieFragment" />
</fragment>
<fragment
android:id="#+id/searchMovieFragment"
android:name="com.example.movieapp.ui.search.SearchMovieFragment"
android:label="SearchMovieFragment" />
</navigation>
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.MainActivity">
<include
layout="#layout/appbar"
android:id="#+id/mainToolBar"/>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/mainToolBar"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var toolbar: Toolbar
private val navController by lazy {
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
}
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
toolbar = findViewById(R.id.mainToolBar)
setSupportActionBar(toolbar)
appBarConfiguration = AppBarConfiguration(navController.graph, null)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.main_menu_bar, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
MainFragment.kt
class MainFragment : Fragment() {
companion object {
fun newInstance() = MainFragment()
}
private lateinit var viewModel: MainViewModel
private lateinit var binding: MainFragmentBinding
private lateinit var navController: NavController
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
binding = DataBindingUtil.inflate(inflater, R.layout.main_fragment, container, false)
setHasOptionsMenu(true)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
navController = Navigation.findNavController(view)
// navController.navigate(R.id.action_mainFragment_to_searchMovieFragment)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
binding.viewModel = viewModel
// TODO: Use the ViewModel
}
}
main_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.example.movieapp.ui.main.MainViewModel" />
</data>
<LinearLayout
android:orientation="vertical"
android:id="#+id/main_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.MainFragment">
<TextView
android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MainFragment1" />
</LinearLayout>
</layout>
The id for a menu item in your file main_menu_bar.xml needs to match the id for the destination(fragment) specified in your navigation graph (nav_graph.xml).
Your main_menu_bar.xml should look something like this:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="#id/searchMovieFragment"
android:icon="#drawable/search"
android:title="#string/menu_search" />
<item
android:id="#id/mainFragment"
android:icon="#drawable/ic_menu_camera"
android:title="#string/menu_home" />
</group>
</menu>
Also, you need to override the onOptionsItemSelected(MenuItem) method and associate your menu items with destinations. Like so:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
}
Reference
You can add a Toolbar on top of the most basic FragmentContainerView, access this toolbar from other fragments, and change the toolbar I created separately according to the fragment in it while opening the relevant fragment as follows.
toolbar = requireActivity().findViewById(R.id.toolbar_base)
toolbar?.menu?.clear()
toolbar?.title = ""
val toolbarFlowFragment = context?.let { getInflateLayout(it, R.layout.toolbar_profile) }
toolbar?.addView(toolbarFlowFragment)

Android Studio Navigation Library problem

I want to use Navigation in my app.
declared in main_activity
<?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"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- Main content -->
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
then I want to go from Fragment1 to Fragment2 using action
UPDATE I am added more code
class LoginFragment2 : Fragment(){
private lateinit var viewModel : LoginViewModel2
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fr_login, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
}
private fun initViews() {
btn_registration.setOnClickListener {
// Navigation.findNavController(it).navigate(R.id.action_loginFragment2_to_newTypeAccountFragment)
// navController = Navigation.findNavController(view)
// findNavController(it).navigate(R.id.action_loginFragment2_to_newTypeAccountFragment)
this.findNavController().navigate(R.id.action_loginFragment2_to_newTypeAccountFragment)
}
}
I tried several options (but not one did not help me)
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.app.peshkariki, PID: 22658
java.lang.IllegalStateException: View androidx.constraintlayout.widget.ConstraintLayout{ca39b84
V.E...... ........ 0,0-720,1360} does not have a NavController set
how to work with it correctly?
Navigation graph (In fact, it is very large, but I will post a small part related to this Fragment)
<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
android:id="#+id/nav_graph"
app:startDestination="#id/mainActivity">
<fragment
android:id="#+id/loginFragment2"
android:name="com.app.peshkariki.newPesh.ui.login.LoginFragment2"
android:label="LoginFragment2"
tools:layout="#layout/fr_login">
<action
android:id="#+id/action_loginFragment2_to_newTypeAccountFragment"
app:destination="#id/newTypeAccountFragment" />
</fragment>
</navigation>
You called NavHostFragment but you don't need to.
Change it to
btn_registration.setOnClickListener {
this.findNavController()
.navigate(R.id.action_loginFragment2_to_newTypeAccountFragment)
}
Put this in onViewCreated:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.my_nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
Also you might wanna do this course

Back button closes app instead of going to previous fragment android navigation component

While creating a very simple sample app, I couldn't wrap my head around why my app is closing when I press the hardware back button on my emulator.
I have 1 mainActivity and 2 fragments.
When I am on the NavigationFragment and press back, the app closes instead of going back to IntermediateFragment.
MainActivity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toolbar.setTitle(R.string.app_name)
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.exampleapplication.MainActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent"
/>
<fragment
android:id="#+id/my_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/main_nav"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
navigation_graph:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_nav"
app:startDestination="#+id/intermediateFragment">
<fragment
android:id="#+id/intermediateFragment"
android:name="com.exampleapplication.IntermediateFragment">
<action
android:id="#+id/action_intermediate_to_navigation"
app:destination="#+id/navigationFragment"
/>
</fragment>
<fragment
android:id="#+id/navigationFragment"
android:name="com.exampleapplication.NavigationFragment"
/>
</navigation>
IntermediateFragment:
class IntermediateFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_intermediate, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_next_fragment.setOnClickListener {
findNavController().navigate(R.id.action_intermediate_to_navigation)
}
}
}
NavigationFragment:
class NavigationFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_navigation, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btn_first_library.setOnClickListener {
findNavController().setGraph(R.navigation.first_library_nav)
}
btn_download_pdf.setOnClickListener {
findNavController().setGraph(R.navigation.download_pdf_nav)
}
}
}
Any ideas?
You're missing one line on your <fragment>:
app:defaultNavHost="true"
As per the Navigation Getting Started guide:
The app:defaultNavHost="true" attribute ensures that your NavHostFragment intercepts the system Back button.
Since you don't set that, Navigtion does not intercept the back button and hence, you only get the default activity behavior (which is closing your activity).

Categories

Resources