Back button not displaying using navigation view and toolbar - android

I have an application with the following hierarchy:
MainActivity (Shows list of dates)
|
ViewPagerFragment (Shows list of children for those dates)
|
ChildFragment (Detail View)
I am trying to implement the navigation view from the design support library, but am having trouble getting the actual navigation on the toolbar to work.
Here is the Main Activity toolbar:
Here is the ViewPagerFragment after navigating there from the main activity, note that there is no back button...
Here is the desired toolbar:
I am adding fragments using the following code:
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, fragment, fragment.getClass().getName())
.addToBackStack(fragment.getClass().getName())
.commitAllowingStateLoss();
Here is the code related to activity startup:
protected void setupActionBar() {
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
And my navigation drawer setup:
protected void setupNavigationDrawer() {
navigationView.setNavigationItemSelectedListener(this);
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.setDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
}
Hitting the hardware back button on the device navigates back properly. I just can't seem to get the back arrow to show up on the drawer toggle... Any suggestions?

To disable the navigation drawer icon and show a different icon instead, you need to call setDrawerIndicatorEnabled(false) on your ActionBarDrawerToggle.
You may also need to call setHomeAsUpIndicator() to specify the icon you want to use instead of the "hamburger" icon.

Have you tried to reach the ActionBar of the Activity ?
in onViewCreated:
Toolbar mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
((Activity) getActivity()).setSupportActionBar(mToolbar);
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Related

Android Studio: NullPointerException with getSupportActionBar()

I want to show an ActionBar in my Activity while only showing a closing symbol. Therefore I used the method getSupportActionBar():
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close);
setTitle("Add Event");
But it throws a NullPointerExeption because apparently there's no ActionBar to call:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.tutorial/com.example.tutorial.AddEventActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.appcompat.app.ActionBar.setHomeAsUpIndicator(int)' on a null object reference
In my MainActivity I implemented a Drawer Navigation where I already used a toolbar that works:
public class MainActivity extends AppCompatActivity {
protected DrawerLayout mDrawer;
private Toolbar toolbar;
private NavigationView nvDrawer;
// Make sure to be using androidx.appcompat.app.ActionBarDrawerToggle version.
private ActionBarDrawerToggle drawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set a Toolbar to replace the ActionBar.
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// This will display an Up icon (<-), we will replace it with hamburger later
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Find our drawer view
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = setupDrawerToggle();
// Setup toggle to display hamburger icon with nice animation
drawerToggle.setDrawerIndicatorEnabled(true);
drawerToggle.syncState();
// Tie DrawerLayout events to the ActionBarToggle
mDrawer.addDrawerListener(drawerToggle);
// Find our drawer view
nvDrawer = (NavigationView) findViewById(R.id.nvView);
// Setup drawer view
setupDrawerContent(nvDrawer);
}
How do I fix that?
Thanks in advance!
Replace this line :
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
with this line :
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
This should solve your problem.
You may try to add following attribute to your MainActivity item under your ActivityManifest.xml
android:theme="#style/Theme.AppCompat.Light.DarkActionBar"
Then try to access it with the getSupportActionBar(). With this way you can choose the activities that you don't or do want to include actionbars by using relevant themes. For example:
<activity
android:name=".SecondActivity"
android:theme="#style/Theme.AppCompat.Light.DarkActionBar"
android:parentActivityName=".MainActivity" />

Cannot restore the navigation drawer button after changing it with a back button

When I go back after changing it to a back button it disappears with the following code:
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(false);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
ActionBarDrawerToggle mToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
mToggle.setDrawerIndicatorEnabled(true);
drawer.setDrawerListener(mToggle);
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
I think that code should make the navigation drawer button to open menu to appear again, but it doesn't.
Any idea of what could be wrong in that code, so the navigation drawer button appears again?
Try like this:
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//.....
Also, you could use androidx.navigation.ui.NavigationUI package to setup your drawer menu.
Here are good articles about NavigationUI.

Android Hamburger Menu and Back Arrow

I want to make on my MainActivity a property navigation for my users with hamburger and back arrow.
When I have only one fragment set hamburger, but if i have more fragments added on my MainActivity, set the back arrow.
How do I implement that?
Here is my implementation...
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private Toolbar toolbar;
private DrawerLayout drawer;
private NavigationView navigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setSupportActionBar(toolbar);
final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
navigationView.setNavigationItemSelectedListener(this);
//TODO: Insert back arrow button if have more than one fragment on backstack
/*getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
if (stackHeight > 0) {
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toggle.setDrawerIndicatorEnabled(false);
}
} else {
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
toggle.setDrawerIndicatorEnabled(true);
}
}
}
});*/
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(), new ListVeiculoFragment(), R.id.container_main);
}
}
Work by creating Interface class:
public interface HideShowIconInterface{
void showHamburgerIcon();
void showBackIcon();
}
Implement Interface in your Activity:
public class YourActivity extends AppCompatActivity implements HideShowIconInterface{
#Override
public void showHamburgerIcon() {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mActionBarDrawerToggle.setDrawerIndicatorEnabled(true);
}
#Override
public void showBackIcon() {
mActionBarDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
In your Fragment, call whatever you want by:
((HideShowIconInterface) getActivity()).showHamburgerIcon();
or
((HideShowIconInterface) getActivity()).showBackIcon();
You have to catch the moment when the numbers of the fragments change and use this code to hide (false) / show (true) the DrawerToggle "Hamburger"
mDrawerToggle.setDrawerIndicatorEnabled(false);
EDIT:
In your Activity (somewhere) you have something like this (where you change current Fragment):
private void selectItem(int position) {
Fragment fragment = new MyFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
}
I would change last line by this:
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment)
.addToBackStack(null)
.commit();
and then check:
if(fragmentManager.getBackStackEntryCount() > 1) mDrawerToggle.setDrawerIndicatorEnabled(false);
setSupportActionBar(toolbar);
toolbar.setTitle(R.string.app_name);
toolbar.setTitleTextColor(getResources().getColor(R.color.colorWhite));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
put this code in your activity where you use humbarger style navigation it work for me.
Actually none of above solutions works fully.
There are couple of issues that have to be considered -
a) if using ActionBarDrawerToggle then getSupportActionBar().setDisplayHomeAsUpEnabled is now working as expected - it actually replaces icon for toggle, but clicks are still handled by toggle plus hamburger icon is hidden when toggle is enabled again
b) As fragments transaction (add, restore form backstack) are done asynchronously, check for actual backstack size has to be done after fragment transaction is done - e.g. from fragments onCreateView
Here is code that works for me (in Kotlin):
override fun onCreate(savedInstanceState: Bundle?) {
// ....
drawerToggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawer_layout.addDrawerListener(drawerToggle)
drawerToggle.setHomeAsUpIndicator(R.drawable.ic_arrow_back_white)
drawerToggle.syncState()
drawerToggle.setToolbarNavigationClickListener {
// whatever action is needed on homeAsUp click
onBackPressed()
}
//And this method should be called from fragment's onCreateView
fun showUpNavigation() {
drawerToggle.isDrawerIndicatorEnabled=supportFragmentManager.getBackStackEntryCount() <= 1
}
You just add
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
For more details see Android - Switch ActionBar Back Button to Navigation Button.

Android: How to disable the ActionBar button that opens navigation drawer

How to disable the ActionBar button that opens navigation drawer?
I use the code below to disable opening the navigation drawer using swipe, but its action bar button (at Top/Left) still active and can be used to open the navigation drawer.
DrawerLayout navigationDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
Try This i think it Will help you
actionBar.setDisplayHomeAsUpEnabled(false);
or you can use this
getActionBar().setDisplayHomeAsUpEnabled(false);
Use this:
getActionBar().setHomeButtonEnabled(false);
You should use setNavigationOnClickListener() on toolbar to avoid Nav Drawer from opening.
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// your code.
}
});
Nav drawer will open just by swiping, and not by clicking on the menu item button.

Disabling navigation drawer, toggling home-button/up-indicator in fragments

The setup
I have an activity whose contentView is an instance of a DrawerLayout, which has a navigation drawer with a drawer indicator displayed in the action bar. The activity contains a Fragment, let's call it ListFragment, which contains a list of options. When an option is clicked, I replace the ListFragment with a DetailFragment.
At this point, I would like to display an "up" navigation option instead of the navigation drawer indicator. I'm able to display the "up" icon if I disable the drawer indicator by calling mDrawerToggle.setDrawerIndicatorEnabled(false), but this only removes the drawer icon--it does not remove the functionality--that is, when I click the caret, the navigation drawer is still opened.
Additionally, in these subviews, I would like to disable the opening of the drawer by dragging from the edge of the screen. I have tried doing this by calling setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) but it doesn't seem to have disabled this functionality.
I have tried extending the ActionBarDrawerToggle class to prevent opening the drawer when the indicator is clicked--however, all that happens is that the overriding action (the "up" navigation) is performed, but the drawer still opens.
I have also implemented the steps in Switching between Android Navigation Drawer image and Up caret when using fragments . It works insofar as displaying the caret goes, but despite overriding the up button functionality, the menu still opens (the app does navigate back--it just also opens the drawer).
Question
So, long story short: is there any (preferably clean and elegant, but at this point I'll go with hacky) way to achieve these things when my layout root is a DrawerLayout:
Replace the drawer indicator with an "up" caret (tentatively doable via mDrawerToggle.setDrawerIndicatorEnabled(false))
Prevent the drawer from opening when the caret is clicked, and instead override with my own "up" functionality
Prevent the drawer from opening when I drag from the edge of the screen.
Edit
All right, it looks like if I both override ActionBarDrawerToggle AND onOptionsItemSelected, the menu does not open when I click the caret. But it still opens if I drag from the edge. Help!
Short Code
public void setDrawerState(boolean isEnabled) {
if ( isEnabled ) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
drawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_UNLOCKED);
drawerToggle.setDrawerIndicatorEnabled(true);
drawerToggle.syncState();
}
else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
drawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
drawerToggle.setDrawerIndicatorEnabled(false);
drawerToggle.syncState();
}
}
This is only part of the solution that I arrived at, but it was quite hard to figure out this bug, so I'm leaving this here for posterity's sake.
This how I was defining the ListView for my navigation drawer:
<ListView
android:id="#+id/listview_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp" />
Even after calling setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) I was still able to slide the drawer open.
However, after changing the layout_gravity to "start" this problem seems to be resolved.
I was able to reproduce this issue in a sample, navigation-drawer-only app, so it does appear to be a reproducible issue not unique to my situation.
Building on sonida's answer. After calling setDrawerIndicatorEnabled(false), onNavigateUp wasn't being called still. So, I just created a new onClickListener that called it:
public void setDrawerState(boolean isEnabled) {
if ( isEnabled ) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
drawerToggle.setDrawerIndicatorEnabled(true);
drawerToggle.syncState();
}
else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
drawerToggle.setDrawerIndicatorEnabled(false);
drawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onSupportNavigateUp();
}
});
drawerToggle.syncState();
}
}
also I think
drawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_UNLOCKED);
has been depreciated, but it works fine without it.
You need to disable swipe and disable the actionbar home button:
Use the below code that builds on the code already given to disable swipe
public void setDrawerState(boolean isEnabled) {
if ( isEnabled ) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerToggle.syncState();
getActivity().getActionBar().setHomeButtonEnabled(true);
}
else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
mDrawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
mDrawerToggle.setDrawerIndicatorEnabled(false);
mDrawerToggle.syncState();
getActivity().getActionBar().setHomeButtonEnabled(false);
}
}
Building on answer by #sonida And after using the tweaks given by #luca992 and #jai.
I tried above suggested codes But the "up" or "Back" arrow in left side of action bar was just not showing up in my app. But luckily I was able to fix that.
I had to add this extra line of code in setNavigationDrawerState() [Ref: android.support.v7.app.ActionBarDrawerToggle.setHomeAsUpIndicator ]
toggle.setHomeAsUpIndicator(R.drawable.ic_keyboard_backspace_white_24dp);
I downloaded the drawable: ic_keyboard_backspace_white_24dp from Material.io
Here is the complete code:
MainActivity.java -> onCreate()
DrawerLayout drawer;
ActionBarDrawerToggle toggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Start: Code automatically generated by Android Studio
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
// End: Code automatically generated by Android Studio
// I had to add this listener as the "back" arrow was totally unresponsive
// Thanks to #luca992
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
// Start: Code automatically generated by Android Studio
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
// End: Code automatically generated by Android Studio
// More custom code for other stuff
// ...
}
MainActivity.java -> setNavigationDrawerState()
public void setNavigationDrawerState(boolean isEnabled) {
if ( isEnabled ) {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
toggle.setDrawerIndicatorEnabled(true);
toggle.syncState();
}
else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
toggle.setDrawerIndicatorEnabled(false);
// the extra line of code goes here
toggle.setHomeAsUpIndicator(R.drawable.ic_keyboard_backspace_white_24dp);
toggle.syncState();
}
MainActivity.java -> onBackPressed()
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if(getSupportFragmentManager().getBackStackEntryCount() > 0){
getSupportFragmentManager().popBackStack();
}else {
super.onBackPressed();
}
}
MainActivity.java -> startFragment() [dummy function for example]
public void startFragment(){
MyFrag myFrag = new MyFrag();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.frag_container ,myFrag)
.addToBackStack(null)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
}
MyFrag.java --> onViewCreated()
#Override
public void onViewCreated (View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
// Say, using an implemented interface Make call to MainActivitiy's setNavigationDrawerState() passing false
// setNavigationDrawerState(false)
// ...
}
MyFrag.java --> onDestroyView()
#Override
public void onDestroyView(){
// Say, using an implemented interface Make call to MainActivitiy's setNavigationDrawerState() passing true
// setNavigationDrawerState(true)
super.onDestroyView();
}

Categories

Resources