I'm having the problem that when I navigate back from a fragment, it doesn't take me back to the previously selected fragment in my BottomNavigation.
I have a single MainActivity that has both a DrawerLayout and a BottomNavigation. The BottomNavigation has 3 items in it corresponding to 3 fragments (Home, Readings, Graph). All 3 are top-level destinations in the app (all 3 have the hamburger menu icon). The DrawerLayout has 1 item in it which opens my AboutFragment.
From the Readings page in the Bottom Navigation, I open the Drawer Layout and click About which opens the AboutFragment. When I then click the 'up' arrow in the AboutFragment it doesn't take me back to Readings, instead it takes me back to Home (the first item in the Bottom Navigation). How can I make it go back to Readings which was the page I was previously on?
MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
setSupportActionBar(mBinding.appBarMain.mainToolbar);
mBottomNav = mBinding.appBarMain.mainBottomBar;
mDrawerLayout = mBinding.drawerLayout;
NavigationView navigationView = mBinding.navView;
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.home, R.id.readings, R.id.graph)
.setOpenableLayout(mDrawerLayout)
.build();
NavController navController = Navigation.findNavController(this, R.id.main_fragments_container);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
NavigationUI.setupWithNavController(mBottomNav, navController);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
NavController navController = Navigation.findNavController(this, R.id.main_fragments_container);
return NavigationUI.onNavDestinationSelected(item, navController)
|| super.onOptionsItemSelected(item);
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.main_fragments_container);
return NavigationUI.navigateUp(navController, mAppBarConfiguration) || super.onSupportNavigateUp();
}
}
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/home">
<fragment
android:id="#+id/home"
android:name="com.myapp.ui.tabs.HomeFragment"
android:label="#string/menu_title_home"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/readings"
android:name="com.myapp.ui.tabs.ReadingsFragment"
android:label="#string/menu_title_readings"
tools:layout="#layout/fragment_readings" />
<fragment
android:id="#+id/graph"
android:name="com.myapp.ui.tabs.GraphFragment"
android:label="#string/menu_title_graph"
tools:layout="#layout/fragment_graph" />
<fragment
android:id="#+id/about"
android:name="com.myapp.ui.about.AboutFragment"
android:label="#string/general_about"
tools:layout="#layout/fragment_about" />
</navigation>
NOTE
As a test, if I make the FAB button (visible on all BottomNavigation fragment screens) go to AboutFragment, then when I click 'up' arrow in the AboutFragment it DOES take me back to Readings. It seems that accessing AboutFragment via the DrawerLayout acts differently to accessing AboutFragment from the FAB.
Can you try to:
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.mainNavHostFragment)
return when(navController.currentDestination?.id) {
R.id.about-> {
navController.popBackStack()
true
}
else -> navController.navigateUp()
}
}
Let me know if it works for you
Answering my own question here for anyone else who has this problem. Solution is to put android:menuCategory="secondary" in the AboutFragment item in the DrawerLayout menu file.
menu_drawer.xml
<item
android:id="#+id/nav_about"
android:menuCategory="secondary"
android:icon="#drawable/vic_about"
android:title="#string/general_about" />
Reason this works is:
By default, the back stack will be popped back to the navigation graph's start destination. Menu items that have android:menuCategory="secondary" will not pop the back stack.
I found the solution in this post https://stackoverflow.com/a/60516769/728002
Related
I am trying to create a new activity with drawer layout. To do this, I used Android Studio's default code generator: File -> New -> Activity -> Navigation Drawer Activity. It created a bunch of files with fragments, drawer, and (jetpack) navigation support and their corresponding resources such as navigation file and layout files. I tried to run the new activity and it installed successfully. The problem is, my navigation drawer is not working. The menu items in my drawer do not trigger any change in host navigation fragment.
I've been stuck for a day already and have tried many solutions already and still, my menu items won't let me navigate to another destination.
Here is my resulting MainActivity.java:
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
private ActivityMainBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarMain.toolbar);
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
.setOpenableLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
return NavigationUI.onNavDestinationSelected(
item,
Navigation.findNavController(this, R.id.nav_host_fragment_content_main)) ||
super.onOptionsItemSelected(item);
}
}
The overridden onOptionsItemSelected() function is from Android's codelab.
Here is my navigation file:
<?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/mobile_navigation"
app:startDestination="#+id/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="com.bicolexpress.delivery.ui.main.ui.home.HomeFragment"
android:label="#string/menu_home"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/nav_gallery"
android:name="com.bicolexpress.delivery.ui.main.ui.gallery.GalleryFragment"
android:label="#string/menu_gallery"
tools:layout="#layout/fragment_gallery" />
<fragment
android:id="#+id/nav_slideshow"
android:name="com.bicolexpress.delivery.ui.main.ui.slideshow.SlideshowFragment"
android:label="#string/menu_slideshow"
tools:layout="#layout/fragment_slideshow" />
</navigation>
Based on the codelab link above:
If NavigationUI finds a menu item with the same ID as a destination on
the current graph, it configures the menu item to navigate to that
destination.
This is true for the generated menu items and destination IDs. But still, does not work. Can anyone point me to what I missed? I desperately need your help.
Android Studio Version: Electric Eel | 2022.1.1
So I tried to copy the layout from codelab. And guess what, the click listeners worked!
I noticed that in codelab's layout, the NavigationView was added into the DrawerLayout as the last child. So I modified my activity_main.xml to:
<?xml version="1.0" encoding="utf-8"?>
<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:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:id="#+id/app_bar_main"
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
I'm setting up a DrawerLayout in my one-activity Navigation component setup, pretty much as outlined on the guide here.
Here is my main activity's code:
class MainActivity : AppCompatActivity(), SubjectFragment.OnListFragmentInteractionListener {
lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
drawerLayout = findViewById<DrawerLayout>(R.id.main_drawer_layout)
val navView = findViewById<NavigationView>(R.id.main_navigation_view)
val sroToolbar = findViewById<Toolbar>(R.id.main_toolbar)
val navController = findNavController(R.id.nav_host_fragment)
navView.setupWithNavController(navController)
setSupportActionBar(sroToolbar)
val appBarConfiguration = AppBarConfiguration(
setOf(R.id.subjectFragment, R.id.aboutFragment, R.id.settingsFragment),
drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.nav_host_fragment).navigateUp(drawerLayout)
}
Above, I'm using AppBarConfiguration to set up the three top level destinations (subjectFragment, aboutFragment, settingsFragment), with the subjectFragment being the home destination in the navigation graph. Here's my nav 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"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/sro_nav_graph"
app:startDestination="#id/subjectFragment">
<fragment
android:id="#+id/subjectFragment"
android:name="black.old.spacedrepetitionowl.SubjectFragment"
android:label="Spaced Repetition Owl: Subjects"
tools:layout="#layout/fragment_subject_list" >
<action
android:id="#+id/action_subjectFragment_to_aboutFragment"
app:destination="#id/aboutFragment" />
<action
android:id="#+id/action_subjectFragment_to_settingsFragment"
app:destination="#id/settingsFragment" />
</fragment>
<fragment
android:id="#+id/aboutFragment"
android:name="black.old.spacedrepetitionowl.AboutFragment"
android:label="Spaced Repetition Owl: About"
tools:layout="#layout/fragment_about" />
<fragment
android:id="#+id/settingsFragment"
android:name="black.old.spacedrepetitionowl.settingsFragment"
android:label="fragment_settings"
tools:layout="#layout/fragment_settings" />
</navigation>
When I start the app, it shows the subjectFragment and the hamburger menu opens the drawer when tapped. This so far is the correct behavior. My drawer then shows three items: Subjects, Settings, and About.
When I select Settings/About from the menu, this then opens the Settings/About fragment correctly.
My problem is, when I'm on those two screens, tapping the hamburger icon will then load the SubjectFragment, instead of making the drawer show up. Here's a GIF of what happened:
The behavior I want is so that the drawer loads each time the hamburger menu is tapped on each of those destinations. What might be the issue here?
Aha! I figured this out by comparing it to a new project made using the 'Navigation Drawer Activity' as project template.
As it turns out, the appBarConfiguration needs to be used as the parameter for navigateUp so that the top-level destinations setup are obeyed:
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
I have to fragments discount fragment and edit service fragment displayed on Edit Service activity.
the back arrow displayed on discount fragment when i back to edit service fragment the arrow disappear i want to display it to navigate the previous activity from edit service activity.
activity layout
.........................................................
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar_hesham"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:title="#string/edit_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent" />
<fragment
android:id="#+id/nav_host_edit_service"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#+id/toolbar_hesham"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="#navigation/edit_service_nav" />
</androidx.constraintlayout.widget.ConstraintLayout>
<include layout="#layout/confirm_request_bottom_sheet"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
activity code
.............................................................
public class EditServicesActivity extends BaseActivity<MainViewModel> {
public Toolbar toolbar;
public NavController navController;
#Override
protected void initActivityComponent() {
component = ProServeTechApp.getComponent(this)
.plus(new ActivityModule(this));
component.inject(this);
}
#Override
protected int getLayout() {
return R.layout.activity_edit_services;
}
#Override
protected Class<MainViewModel> getViewModelClass() {
return MainViewModel.class;
}
#Override
protected void initActivity() {
viewModel.getRequestDetails(getIntent().getExtras().getString("requestId"), String.valueOf(0));
viewModel.getIssues(getIntent().getStringExtra("requestId"));
toolbar = findViewById(R.id.toolbar_hesham);
setSupportActionBar(toolbar);
navController = Navigation.findNavController(this, R.id.nav_host_edit_service);
NavigationUI.setupWithNavController(toolbar, navController );
}
}
navigation
........................................
<?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/edit_service_nav"
app:startDestination="#id/edi_service_fragment">
<fragment
android:id="#+id/edi_service_fragment"
android:name="com.unicomg.proservetech.ui.requestdetails.edit.service.fragments.EditServiceFragment"
android:label="#string/edit_service"
tools:layout="#layout/edit_service_fragment">
<action
android:id="#+id/action_edi_service_fragment_to_discount_fragment"
app:destination="#id/discount_fragment"
app:enterAnim="#anim/slide_up"
app:exitAnim="#anim/slide_bottom"
app:popEnterAnim="#anim/slide_up"
app:popExitAnim="#anim/slide_bottom" />
</fragment>
<fragment
android:id="#+id/discount_fragment"
android:name="com.unicomg.proservetech.ui.requestdetails.edit.service.fragments.DiscountFragment"
android:label="#string/add_discount"
tools:layout="#layout/discount_fragment">
</fragment>
</navigation>
As per the setupWithNavController(Toolbar, NavController) documentation:
The start destination of your navigation graph is considered the only top level destination. On all other destinations, the Toolbar will show the Up button.
If you want to also show the Up button on your start destination (i.e., to go to the previous activity), you'd want to use the version that takes an AppBarConfiguration.
As per the Update UI components documentation on AppBarConfiguration, AppBarConfiguration allows you to set exactly what destinations you want as top level destinations. To get the Up button to show on every destination, you'd use an empty set of top level destinations:
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder().build();
Note that since you're using setSUpportActionBar(), you should follow the Action Bar documentation and use the setupActionBarWithNavController() method rather than the Toolbar version. You must also override onSupportNavigateUp() to handle the up button.
Therefore your complete code would look like:
public class EditServicesActivity extends BaseActivity<MainViewModel> {
public Toolbar toolbar;
public AppBarConfiguation appBarConfiguation;
public NavController navController;
#Override
protected void initActivityComponent() {
component = ProServeTechApp.getComponent(this)
.plus(new ActivityModule(this));
component.inject(this);
}
#Override
protected int getLayout() {
return R.layout.activity_edit_services;
}
#Override
protected Class<MainViewModel> getViewModelClass() {
return MainViewModel.class;
}
#Override
protected void initActivity() {
viewModel.getRequestDetails(getIntent().getExtras().getString("requestId"), String.valueOf(0));
viewModel.getIssues(getIntent().getStringExtra("requestId"));
toolbar = findViewById(R.id.toolbar_hesham);
setSupportActionBar(toolbar);
navController = Navigation.findNavController(this, R.id.nav_host_edit_service);
appBarConfiguration = new AppBarConfiguration.Builder().build();
NavigationUI.setupActionBarWithNavController(this, navController,
appBarConfiguration);
}
#Override
public boolean onSupportNavigateUp() {
return NavigationUI.navigateUp(navController, appBarConfiguration)
|| super.onSupportNavigateUp();
}
}
I have a basic app, containing a drawer layout. Each option in the drawer opens up a new fragment page for the user to view. Here is the drawer layout code.
<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:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
Here is the app_bar_main.xml code.
<androidx.coordinatorlayout.widget.CoordinatorLayout 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=".DashBoardActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And here is the content_main.xml. And also the main activity DashBoardActivity.kt
class DashBoardActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dashboard)
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)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_company_emissions, R.id.nav_your_emissions, R.id.nav_contact,
R.id.nav_privacy_policy
), 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()
}
}
From my understanding when you click a button in the drawer layout the fragment in the host fragment is replaced with the relevant clicked on fragment.
My questions is... How do I programatically put another fragment in this nav host view which hasn't been set up with the drawer layout. My problem is one of the fragments contains a profile for a user with an edit button. I want to open a new fragment when the edit button is clicked and wish for the user to still have access to the drawer when they do so don't want to go to another activity.
In my mind I just want to replace the profile_fragment with the edit_fragment. But when I've tried something like this below its placed the fragment onto of the profile one so that you have this weird looking screen with two fragments on top of one another.
val frag: Fragment = EditYourEmissionsFragment()
val fragMan:FragmentManager = activity!!.supportFragmentManager
val fragTran: FragmentTransaction = fragMan.beginTransaction()
fragTran.add(R.id.nav_host_fragment, frag)
fragTran.addToBackStack(null)
fragTran.commit()
I'm still a relative novice when it comes to Android and Kotlin so am struggling to understand how I would go about doing my user case.
Scenario for trying to help paint a picture of what I want to happen:
User loads app and lands on home_fragment.
Opens drawer menu, clicks profile_fragment.
Once in profile_fragment opens the user presses edit.
A new fragment takes over the screen, but retains the ability to open the menu drawer.
User can now either open the drawer menu and navigate to other places across the app. Or save their profile and get taken back to the profile_fragment.
Thank you in advance for any help. Apologies if its not particularly clear.
include the EditYourEmissionsFragment in the navigationGraph like this:
<fragment
android:id="#+id/EditYourEmissionsFragment"
android:name="com.example.application.EditYourEmissionsFragment"
android:label="Edit Profile"
tools:layout="#layout/fragment_edit_omissions"/>
and then on your ProfileFragment set the onClick to open the destination like this;
val navController = Navigation.findNavController(view)
navController.navigate(R.id.EditYourEmissionsFragment)
and in your MainActivity
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.my_nav_host)
return navController.navigateUp(myAppBarConfiguration) || super.onSupportNavigateUp()
}
Hi I'm trying to use new arch components in my project. Short description what I want to achieve:
When user is on MainFragment I want to display navigation icon (Hamburger) on BottomAppBar. User is able to click navigation icon and display BottomNavigationDrawer
When user select some menu item, or click something on MainFragment he is moved to another fragment, let say DebtDetailsFragment. Then Hamburger should be replaced with 'Back arrow' by NavigationController
Below I pasted my MainActivity code. When I comment line with navigation controller, the Hamburger icon is visible and BottomNavigationDrawer is able to display.
But when I uncomment this line, the Hamburger disappear because NavigationController knows nothing about NavigationView used in BottomNavigationDrawer. I don't use DrawerLayout, so controller thinks Hamburger is not needed.
Method setupWithNavController can control Hamburger icon and back arrow, but I have to provide DrawerLayout as parameter which I don't use.
Documentation for this method:
The Toolbar will also display the Up button when you are on a non-root destination and the drawer icon when on the root destination, automatically animating between them. This method will call [DrawerLayout.navigateUp] when the navigation icon is clicked.
So the question is, how to display Hamburger icon when NavigationController is connected with BottomAppBar but without DrawerLayout? I will handle hamburger click myself in onOptionsItemSelected method.
class MainActivity : BaseActivity() {
#Inject
lateinit var viewModelProvider: ViewModelProvider.Factory
private val viewModel: MainActivityViewModel by lazy {
ViewModelProviders.of(this, viewModelProvider).get(MainActivityViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(bottomAppBar)
val navController = findNavController(R.id.main_nav_host_fragment)
//bottomAppBar.setupWithNavController(navController)
onDestroyDisposables += viewModel.uiStateObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(::render, Timber::e)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.bottomappbar_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
android.R.id.home -> {
val bottomNavDrawerFragment = BottomNavigationDrawerFragment()
bottomNavDrawerFragment.show(supportFragmentManager, bottomNavDrawerFragment.tag)
}
}
return super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.main_nav_host_fragment).navigateUp()
}
}
Without setted Navigation controller:
BottomNavigationDrawer
With setted NavigationController - Hamburger invisible.
The BottomAppBar should never display an Up button as per the anatomy of the BottomAppBar - it should only ever display the drawer icon. As seen in the behavior documentation, the Up button should be displayed in a top Toolbar.
Therefore, you should never be calling bottomAppBar.setupWithNavController(navController), but instead calling setupWithNavController(navController) using whatever top Toolbar you have.
To set up your BottomAppBar, you should instead set your own drawer icon and handle clicks on the drawer icon yourself.
The DrawerArrowDrawable class is available to give you a correct drawer icon:
val icon = DrawerArrowDrawable(bottomAppBar.context)
bottomAppBar.navigationIcon = icon
I implemented the BottomAppBar with Jetpack navigation drawer component as following way in my app.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomAppBar bottomAppBar = findViewById(R.id.bottomAppBar);
setSupportActionBar(bottomAppBar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
NavigationView navigationView = findViewById(R.id.nav_view);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupWithNavController(navigationView, navController);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
return NavigationUI.navigateUp(navController, drawer)
|| super.onSupportNavigateUp();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
app_bar_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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=".MainActivity">
<include layout="#layout/content_main" />
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:layout_gravity="bottom"
app:fabCradleVerticalOffset="16dp"
app:navigationIcon="#drawable/ic_baseline_menu_24"
app:navigationContentDescription="#string/nav_header_desc"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
style="#style/Widget.MaterialComponents.BottomAppBar.Colored"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_menu_send"
app:layout_anchor="#id/bottomAppBar"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
The result will be like this