Hamburger icon not showing correctly after toolbar replacement - android

I have an activity that has a fragment layout dedicated to the toolbar. In the center we have a normal nav_host container.
The activity contains one fragment that correctly shows the hamburger. If I click a button it gets replaced from a second fragment that replace the old toolbar with a new one. After clicking back the new toolbar is replaced by the old one.
The problem is that the hamburger icon doesn't show up and the toolbar doesn't work as expected. Ideas?
This is the code in the activity:
open fun setupToolbar() {
initialToolbar = ToolbarFragment()
setToolbarFragment(initialToolbar){
setNavController()
}
}
fun setToolbarFragment(fragment: Fragment, callback: () -> (Unit) = {}) {
supportFragmentManager
.beginTransaction()
.replace(R.id.toolbarContainer, fragment)
.runOnCommit {
callback.invoke()
}.commit()
}
private fun setNavController() {
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = setFragmentsWithHamburgerMenu(navController)
toolbar.setupWithNavController(navController, appBarConfiguration)
}
fun setFragmentsWithHamburgerMenu(navController: NavController): AppBarConfiguration {
return AppBarConfiguration(
setOf(
R.id.analyticsFragment,
R.id.routinesFragment,
R.id.currentRunFragment,
R.id.myMapsFragment,
R.id.myRobotsFragment
),
drawer_layout
)
}
This is the code instead of the second fragment:
override fun onResume() {
super.onResume()
val fragment = SearchToolbarFragment(searchHint, this::onQueryTextChange)
baseActivity.setToolbarFragment(fragment) {
// other stuff
}
}
override fun onPause() {
super.onPause()
baseActivity.setupToolbar()
}
This instead is my activity layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="viewModel" type="[package].DashboardViewModel" />
</data>
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/toolbarContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"/>
<fragment
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottom_nav"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbarContainer" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav"
style="#style/BottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
app:itemBackground="#color/white"
app:itemTextColor="#color/button_view_item"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/menu_bottom_nav" />
<LinearLayout
android:id="#+id/progressMaskLayout"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbarContainer">
<include layout="#layout/progress_mask" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<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">
<include
bind:viewModel="#{viewModel}"
layout="#layout/element_navigation_bar"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
</layout>

To avoid the problem I just added a fragment over the previous one and I removed the added one.
Like this:
fun addToolbarFragment(fragment: Fragment, callback: () -> (Unit) = {}) {
supportFragmentManager
.beginTransaction()
.add(R.id.toolbarContainer, fragment)
.runOnCommit {
callback.invoke()
}.commit()
}
fun removeToolbarFragment(fragment: Fragment, callback: () -> (Unit) = {}) {
supportFragmentManager
.beginTransaction()
.remove(fragment)
.runOnCommit {
callback.invoke()
}.commit()
}
In this way, all the customization done in the first toolbar won't be lost.

First, you're using Android jetpack navigation component but also using fragment manager to manually do fragment transactions. You're defying the purpose of using the jetpack navigation component. That's the whole point of using the navigation library so that we don't have to manually do the fragment transactions. What you have to do here is put your toolbar in the main_activity.xml so that all fragments can inherit it.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/Drawer_Main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/Layout_Coordinator_Main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/Toolbar_Main"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary">
<TextView
android:id="#+id/Toolbar_Main_Title"
style="#style/Locky.Text.Toolbar.TitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/app_name" />
</com.google.android.material.appbar.MaterialToolbar>
<androidx.core.widget.NestedScrollView
android:id="#+id/Nested_Scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:fillViewport="true">
<fragment
android:id="#+id/Navigation_Host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation_drawer_main" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/FAB_Add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:srcCompat="#drawable/ic_add" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/Navigation_View"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:clipToPadding="false"
android:paddingStart="0dp"
android:paddingEnd="16dp"
app:headerLayout="#layout/drawer_header"
app:menu="#menu/menu_drawer_main" />
</androidx.drawerlayout.widget.DrawerLayout>
</layout>

Related

Android Navigation Error: You must call setGraph() before calling getGraph()

I'm trying to make an memo app, and this is my first time with application programming.
When I tried to run the code on my device it just dies after showing the IntroActivity and the error log says: "You must call setGraph() before calling getGraph()"
Below is the code.
class ListActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityListBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityListBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
val navController = findNavController(R.id.nav_host_fragment_content_list)
appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
binding.fab.setOnClickListener { view ->
val intent=Intent(applicationContext, DetailActivity::class.java)
startActivity(intent)
}
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_list)
return navController.navigateUp(appBarConfiguration)
|| super.onSupportNavigateUp()
}
}
When I googled about this error there were only answers about androidx.navigation version 2.3.0-alpha2, so I checked my build.gradle.
I was using 2.5.0, the latest version.
How else can I solve this problem?
activity_list.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=".ListActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/Theme.DimoMemo.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/Theme.DimoMemo.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/content_list" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="#dimen/fab_margin"
android:layout_marginBottom="16dp"
app:srcCompat="#drawable/ic_add"
android:layout_marginRight="#dimen/fab_margin" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
content_list.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/contentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<fragment
android:id="#+id/nav_host_fragment_content_list"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp" />
</FrameLayout>
check if the layout contains:
app:navGraph="#navigation/nav_graph"
app:defaultNavHost="true"
your nav_host_fragment_content_list must look like:
<fragment
android:id="#+id/nav_host_fragment_content_list"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:navGraph="#navigation/your_nav_graph"
app:defaultNavHost="true" />
https://developer.android.com/guide/navigation/navigation-getting-started

Navigation Component action won't hide the original fragment before showing the destination fragment [duplicate]

I'm trying the jetpack navigation and can't show the navigation back button when I move to a new fragment.
NavigationActivity.kt
class NavActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigation)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
val host: NavHostFragment = supportFragmentManager
.findFragmentById(R.id.navigation_graph) as NavHostFragment? ?: return
// Set up Navigation
val navController = host.navController
setupActionBarWithNavController(navController)
setupBottomNavMenu(navController)
}
private fun setupActionBarWithNavController(navController: NavController) {
setupActionBarWithNavController(this, navController)
}
private fun setupBottomNavMenu(navController: NavController) {
findViewById<BottomNavigationView>(R.id.bottom_nav_view)?.let { bottomNavView ->
NavigationUI.setupWithNavController(bottomNavView, navController)
}
}
}
activity_navigation.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".views.NavActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:background="?attr/colorPrimary"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:layout_width="match_parent">
</androidx.appcompat.widget.Toolbar>
<fragment
android:id="#+id/navigation_graph"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
app:navGraph="#navigation/navigation_graph"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
navigation_graph.xml
<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"
app:startDestination="#+id/launcher_home">
<fragment
android:id="#+id/launcher_home"
android:name="com.noisyninja.androidlistpoc.views.main.MainFragment"
android:label="#string/app_name"
tools:layout="#layout/fragment_main">
<action
android:id="#+id/next_action"
app:destination="#+id/detailFragment"
app:enterAnim="#anim/slide_in_right"
app:exitAnim="#anim/slide_out_left"
app:popEnterAnim="#anim/slide_in_left"
app:popExitAnim="#anim/slide_out_right" />
</fragment>
<fragment
android:id="#+id/detailFragment"
android:name="com.noisyninja.androidlistpoc.views.detail.DetailFragment"
android:label="DetailFragment" />
</navigation>
code for navigation:
/**
* opens detail activity
*/
override fun showDetail(view: View, me: Me) {
var bundle = Bundle()
bundle.putString("key", "value")
Navigation.findNavController(view).navigate(R.id.next_action, bundle, null)
}
As above when navigation to the second fragment the toolbar goes missing entirely and doesn't show the back button.
Hitting the hardware back button also doesn't pop the detail view.
The first hit has no effect, the second hit quits the app.
Override this method in your Activity with nav_host_fragment
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
Edit: Your DetailFragment contains the line
DataBindingUtil.setContentView<FragmentDetailBinding>(requireActivity(),
R.layout.fragment_detail)
which is resetting the content of your Activity to only be your fragment_detail layout, wiping out the NavHostFragment and everything else.
You should be using DataBindingUtil.bind<FragmentDetailBinding>(view)!! instead.
Original answer (you should still do this, but the above answer is actually what solves the problem)
Your ConstraintLayout is missing quite a few constraints (your views should be a vertical chain, where every app:layout_constraintTop_toBottomOf has an alternative app:layout_constraintBottom_toTopOf on the other element, etc.).
Since you have a single set of three vertically aligned items, you don't need a ConstraintLayout - just a LinearLayout is enough:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
tools:context=".views.NavActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:layout_width="match_parent"/>
<fragment
android:id="#+id/navigation_graph"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation_graph"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
</LinearLayout>

Why my app seems not responding after adding fragment in my mainActivity when implementing Navigation Graph?

I am trying to learn how to use the navigation controller. and the problem is, My app seems not responding, it takes a very long time to show the main activity, and I can't also press the back button (seems not active)
here is the screenshot of my navigation graph, I am trying to set the host fragment in my Main Activity, as you can see, it seems a little bit weird that the bottom navigation view and the toolbar seem double on the NavHostFragment.
here is the screenshot of my main activity:
here is my mainActivity xml:
<android.support.constraint.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.Toolbar
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="?attr/actionBarTheme"
android:minHeight="?attr/actionBarSize"
android:id="#+id/toolbar"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<fragment
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/nav_host_fragment"
app:layout_constraintBottom_toTopOf="#+id/bottom_nav"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/navigation_graph"
app:defaultNavHost="true"
/>
<android.support.design.widget.BottomNavigationView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#color/colorPrimary"
app:itemIconTint="#color/color_bottom_view_navigation"
app:itemTextColor="#color/color_bottom_view_navigation"
app:menu="#menu/menu_bottom_view"
app:labelVisibilityMode="labeled"
android:id="#+id/bottom_nav"/>
</android.support.constraint.ConstraintLayout>
and here is the xml of navigation graph:
<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/navigation_graph"
app:startDestination="#id/mainActivity">
<activity android:id="#+id/mainActivity" android:name="com.muchammadagunglaksana.navcontroller.MainActivity"
android:label="activity_main" tools:layout="#layout/activity_main"/>
</navigation>
and here is my MainActivity class:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
setupBottomNavMenu(navController)
setupActionBar(navController)
}
private fun setupBottomNavMenu(navController: NavController) {
bottom_nav?.let {
NavigationUI.setupWithNavController(it, navController)
}
}
private fun setupActionBar(navController: NavController) {
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_toolbar, menu)
return true
}
}
what went wrong in here?
It is because you are adding the same activity(mainActivity) as your start destination inside nav host fragment that is also part of main activity.
Solution is you have to remove main activty as your starting destination and add anotehr fragment/activity in it. 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/navigation_graph"
app:startDestination="#id/mainFragment">
<fragment android:id="#+id/mainFragment"
android:name="com.cinderellaman.general.ui.fragments.MainFragment"
android:label="main_fragment"
tools:layout="#layout/main_fragment"/></navigation>

How to make navigation drawer and bottom navigation with the same app?

I'm trying to use navigation drawer and bottom bar nav in my app.therefore i have created navigation activity first.then i tried to add bottom bar nav to that same activity. I want to develop like this app:
without BottomNavigationView in Activity.xml,app is working.but when i add BottomNavigationView inside Activity.xml app crashed.nothing showing in logcat.
how can i use both bottombar nav and navigation drawer in same activity,please give me an simple example? thx
I am using Navigation Architecture Component following version:
def nav_version = "2.0.0"
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
And below is a simple code to use BottomNavigation and Navigation Drawer
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
private static final String TAG = "debinf MainActivity";
//public static final String FRAGMENT_KEY = "fragment";
private BottomNavigationView bottomNavigationView;
private NavigationView navigationView;
private DrawerLayout drawerLayout;
private NavController navController;
private AppBarConfiguration appBarConfiguration;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate: ");
bottomNavigationView = (BottomNavigationView) findViewById(R.id.main_bottomnav);
navigationView = (NavigationView) findViewById(R.id.main_sidebar);
drawerLayout = (DrawerLayout) findViewById(R.id.main_drawer);
setupNavigation();
}
private void setupNavigation() {
Log.i(TAG, "setupNavigation: ");
navController = Navigation.findNavController(this, R.id.main_fragment);
appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph()) //Pass the ids of fragments from nav_graph which you dont want to show back button in toolbar
.setDrawerLayout(drawerLayout)
.build();
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration); //Setup toolbar with back button and drawer icon according to appBarConfiguration
NavigationUI.setupWithNavController(navigationView, navController);
NavigationUI.setupWithNavController(bottomNavigationView, navController);
/*
** Listener for bottomNavigation must be called after been setupWithNavController
** This command will override NavigationUI.setupWithNavController(bottomNavigationView, navController)
** and the automatic transaction between fragments is lost
* */
//bottomNavigationView.setOnNavigationItemSelectedListener(this);
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public void onBackPressed() {
Log.i(TAG, "onBackPressed: ");
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
Log.i(TAG, "onBackPressed: DRAWER IS OPEN - CLOSING IT");
drawerLayout.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onSupportNavigateUp() {
Log.i(TAG, "onSupportNavigateUp: ");
// replace navigation up button with nav drawer button when on start destination
return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp();
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Log.i(TAG, "onNavigationItemSelected: SIDE BAR");
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
}
// https://stackoverflow.com/questions/55990820/how-to-use-navigation-drawer-and-bottom-navigation-simultaneously-navigation-a
// https://stackoverflow.com/questions/58345696/how-to-use-android-navigation-component-bottomnavigationview-navigationview
// https://stackoverflow.com/questions/55667686/how-to-coordinate-a-navigation-drawer-with-a-buttom-navigation-view
// https://ux.stackexchange.com/questions/125627/is-it-okay-to-use-both-nav-drawer-and-bottom-nav-in-home-screen-of-an-android-ap?newreg=da5d1cea03db496982a00b256647728d
if (menuItem.getItemId() == R.id.main_menusidehome) {
Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
startActivity(intent);
Log.i(TAG, "onNavigationItemSelected: conta");
}
if (menuItem.getItemId() == R.id.main_menusideshop) {
Log.i(TAG, "onNavigationItemSelected: compra");
}
if (menuItem.getItemId() == R.id.main_menusidesearch) {
Log.i(TAG, "onNavigationItemSelected: estatistica");
}
return true;
}
}
And below is acitivity_main.xml :
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/main_drawer"
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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/main_fragment"
android:layout_width="0dp"
android:layout_height="0dp"
android:name="androidx.navigation.fragment.NavHostFragment"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/main_bottomnav"
app:defaultNavHost="true"
app:navGraph="#navigation/mainnav_graph"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/main_bottomnav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/main_navmenu"
android:background="#color/colorAccent"
app:itemIconTint="#drawable/botton_item_color"
app:itemTextColor="#drawable/botton_item_color">
</com.google.android.material.bottomnavigation.BottomNavigationView>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="#+id/main_sidebar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/main_sidebarmenu"/>
</androidx.drawerlayout.widget.DrawerLayout>
I hope it helps!
If you using includes. Just wrap app bar include with bottom navigation in some layout. For example I'm using ConstraintLayout for most of time.
content_main
<?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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/view_pager_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
app_bar_main
<?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">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/gradient_main"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/material_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:titleTextColor="#color/white" />
</com.google.android.material.appbar.AppBarLayout>
<include
android:id="#+id/content_main_include"
layout="#layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
activity_main
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.android.tool.ui.activty.main.MainActivity"
tools:openDrawer="start">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/app_bar_include"
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="#menu/menu_main" />
</androidx.constraintlayout.widget.ConstraintLayout>
<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"
app:headerLayout="#layout/nav_header_example"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
That's all.
Add a parent to <include ..../> then add BottomNavigationView
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#color/colorPrimary"
app:itemTextColor="#color/colorAccent"
app:menu="#menu/bottom_navigation_menu"/>
</RelativeLayout>
Use TabLayout instead of bottom navigation
TabLayout is better and easier
create root.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="#+id/drawerlayout"
android:layout_height="match_parent">
<include layout="#layout/activity_main"/>
<include layout="#layout/navi_drawer"/>
</android.support.v4.widget.DrawerLayout>
create navi_drawer
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:background="?attr/navigationBackground"
android:orientation="vertical">
</LinearLayout>
and activity_main.xml
<LinearLayout 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"
android:background="?attr/backgroundActivity"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</android.support.v4.view.ViewPager>
<LinearLayout
android:id="#+id/lnrTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="rtl"
android:orientation="vertical"
app:layout_anchor="#+id/viewpager"
app:layout_anchorGravity="bottom|center">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#color/dividers_color_dark"
app:layout_anchor="#+id/viewpager"
app:layout_anchorGravity="bottom|center" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
app:tabBackground="?attr/backgroundTab"
app:tabContentStart="9dp"
app:tabGravity="fill"
app:tabIndicatorColor="#color/colorAccent"
app:tabIndicatorHeight="1dp"
app:tabMode="scrollable" />
</LinearLayout>
</LinearLayout>
then MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.root);
//config your TabLayout
}

Android architecture component navigation: toolbar back button missing, back not working

I'm trying the jetpack navigation and can't show the navigation back button when I move to a new fragment.
NavigationActivity.kt
class NavActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigation)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
val host: NavHostFragment = supportFragmentManager
.findFragmentById(R.id.navigation_graph) as NavHostFragment? ?: return
// Set up Navigation
val navController = host.navController
setupActionBarWithNavController(navController)
setupBottomNavMenu(navController)
}
private fun setupActionBarWithNavController(navController: NavController) {
setupActionBarWithNavController(this, navController)
}
private fun setupBottomNavMenu(navController: NavController) {
findViewById<BottomNavigationView>(R.id.bottom_nav_view)?.let { bottomNavView ->
NavigationUI.setupWithNavController(bottomNavView, navController)
}
}
}
activity_navigation.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".views.NavActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:background="?attr/colorPrimary"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:layout_width="match_parent">
</androidx.appcompat.widget.Toolbar>
<fragment
android:id="#+id/navigation_graph"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbar"
app:navGraph="#navigation/navigation_graph"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
navigation_graph.xml
<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"
app:startDestination="#+id/launcher_home">
<fragment
android:id="#+id/launcher_home"
android:name="com.noisyninja.androidlistpoc.views.main.MainFragment"
android:label="#string/app_name"
tools:layout="#layout/fragment_main">
<action
android:id="#+id/next_action"
app:destination="#+id/detailFragment"
app:enterAnim="#anim/slide_in_right"
app:exitAnim="#anim/slide_out_left"
app:popEnterAnim="#anim/slide_in_left"
app:popExitAnim="#anim/slide_out_right" />
</fragment>
<fragment
android:id="#+id/detailFragment"
android:name="com.noisyninja.androidlistpoc.views.detail.DetailFragment"
android:label="DetailFragment" />
</navigation>
code for navigation:
/**
* opens detail activity
*/
override fun showDetail(view: View, me: Me) {
var bundle = Bundle()
bundle.putString("key", "value")
Navigation.findNavController(view).navigate(R.id.next_action, bundle, null)
}
As above when navigation to the second fragment the toolbar goes missing entirely and doesn't show the back button.
Hitting the hardware back button also doesn't pop the detail view.
The first hit has no effect, the second hit quits the app.
Override this method in your Activity with nav_host_fragment
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
Edit: Your DetailFragment contains the line
DataBindingUtil.setContentView<FragmentDetailBinding>(requireActivity(),
R.layout.fragment_detail)
which is resetting the content of your Activity to only be your fragment_detail layout, wiping out the NavHostFragment and everything else.
You should be using DataBindingUtil.bind<FragmentDetailBinding>(view)!! instead.
Original answer (you should still do this, but the above answer is actually what solves the problem)
Your ConstraintLayout is missing quite a few constraints (your views should be a vertical chain, where every app:layout_constraintTop_toBottomOf has an alternative app:layout_constraintBottom_toTopOf on the other element, etc.).
Since you have a single set of three vertically aligned items, you don't need a ConstraintLayout - just a LinearLayout is enough:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical"
tools:context=".views.NavActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:layout_width="match_parent"/>
<fragment
android:id="#+id/navigation_graph"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation_graph"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_nav" />
</LinearLayout>

Categories

Resources