I am trying to change hamburger menu icon for NavigationView but I am unable to do so.
Here is what I have tried so far
I have a base activity where nav drawer setup is done. Here is relevant piece of code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_base_nav);
setSupportActionBar(toolbar);
setupDrawer();
}
private void setupDrawer() {
mDrawerLayout.setDrawerListener(this);
mDrawerToggle = new ActionBarDrawerToggle(this,
mDrawerLayout,
R.string.open,
R.string.close);
mDrawerToggle = new ActionBarDrawerToggle(mContext,
mDrawerLayout,
R.string.open,
R.string.close);
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(false);
mDrawerToggle.setDrawerIndicatorEnabled(false);
mDrawerToggle.setHomeAsUpIndicator(R.drawable.ic_share_48pt_2x);
}
mDrawerToggle.syncState();
mNavigationView.setNavigationItemSelectedListener(
menuItem -> {
mMenuItem = menuItem.getItemId();
mDrawerUtil.onNavMenuItemClicked(mMenuItem);
mDrawerLayout.closeDrawers();
return true;
});
}
#Override
public void setContentView(int layoutResID) {
getLayoutInflater().inflate(layoutResID, mContainer);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
However it doesn't seem to be working for me. I have also tried calling setDrawerIndicatorEnabled(false) and setHomeAsUpIndicator(R.drawable.ic_share_48pt_2x) on SupportActionBar but that also doesn't work.
The following code works nicely for me,
protected void onCreate(Bundle savedInstanceState) {
...
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDefaultDisplayHomeAsUpEnabled(false);
toggle.setDrawerIndicatorEnabled(false);
toggle.setHomeAsUpIndicator(R.drawable.ic_custom_drawer_icon);
...
}
I also had to add a toolbar navigation click listener to listen for click events on the custom drawer icon
protected void onCreate(Bundle savedInstanceState) {
...
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
drawer.openDrawer(GravityCompat.START);
}
}
});
...
}
Finally, I can update the icon dynamically as
toggle.setHomeAsUpIndicator(R.drawable.ic_new_icon);
Just use this :
toolbar.post(new Runnable() {
#Override
public void run() {
Drawable d = ResourcesCompat.getDrawable(getResources(), R.mipmap.ic_launcher, null);
toolbar.setNavigationIcon(d);
}
});
You dont need to handle setToolbarNavigationClickListener which is in accepted answer.
Here's what works for me:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
//toggle.isDrawerSlideAnimationEnabled = false
toggle.isDrawerIndicatorEnabled = false
toggle.setToolbarNavigationClickListener {
if (drawer_layout.isDrawerOpen(GravityCompat.START))
drawer_layout.closeDrawer(GravityCompat.START)
else
drawer_layout.openDrawer(GravityCompat.START)
}
toggle.setHomeAsUpIndicator(AppCompatResources.getDrawable(this, R.drawable.ic_android_black_24dp))
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
nav_view.setNavigationItemSelectedListener(this)
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
...
}
drawer_layout.closeDrawer(GravityCompat.START)
return true
}
Have you try to look at the documentation ?
http://developer.android.com/training/implementing-navigation/nav-drawer.html
I've found this piece of code in it :
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
/** Called when a drawer has settled in a completely closed state.*/
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
With custom Toolbar
Set your Toolbar as ActionBar.
Then add homeicon using actionBar.setDisplayHomeAsUpEnabled(true);
Code snippet:
Toolbar toolbar = findViewById(R.id.customFBToolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.myham); // This is the line where you set the drawable
actionBar.setDisplayShowTitleEnabled(false);
Result:
Full code:
custom_toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/psyche_toolbar"
android:layout_width="match_parent"
android:layout_height="56sp"
android:background="#color/colorPrimaryDark"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
tools:ignore="title"
tools:targetApi="lollipop">
<TextView
android:text="Facebook"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:layout_gravity="center"
android:textStyle="bold"
android:textSize="20sp"
/>
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_gravity="end"
android:layout_marginEnd="20sp"
android:elevation="4dp"
android:src="#android:drawable/ic_dialog_email"/>
</androidx.appcompat.widget.Toolbar>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.customFBToolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.myham); // This is the line where you set the drawable
actionBar.setDisplayShowTitleEnabled(false);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Toast.makeText(MainActivity.this, "Home button clicked", Toast.LENGTH_SHORT).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/drawer_layout">
<include layout="#layout/custom_toolbar"
android:id="#+id/customFBToolbar"
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
You can use this method to set navigation with icons in the whole application, I am sure it will work for you.its simple method
mainActivity.java
getSupportActionBar().bar.setDisplayHomeAsUpEnabled(true);//Doing so will make the icon appear
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
#Override
public void onDestinationChanged(#NonNull NavController navController, #NonNull NavDestination navDestination, #Nullable Bundle bundle) {
if ( mAppBarConfiguration.getTopLevelDestinations().contains(navDestination.getId())){
toolbar.setNavigationIcon(R.drawable.yout_drawer_icon);
} else {
toolbar.setNavigationIcon(R.drawable.you_back_icon);
}
}
});
Related
I started creating of app which use one activity (Navigation Drawer) and many fragments.
But I unable to use toolbar back button to navigate back from fragments. Hardware back button works perfectly. I know that I need to override onOptionsItemSelected, catch android.R.id.home, check if there are something in back stack and than pop it. After changing fragment, "burger" button changes to "back arrow", but when I click on it onOptionsItemSelected never fired, just opens the NavigationDrawer menu.
Here the code from activity:
public class NavDrawerActivity extends AppCompatActivity implements ... {
NavigationView navigationView;
BottomNavigationView bottomNavigationView;
ActionBarDrawerToggle toggle;
FragmentManager fragmentManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nav_drawer);
fragmentManager = getSupportFragmentManager();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
// Set back button
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (fragmentManager.getBackStackEntryCount() > 0) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
toggle.syncState();
}
}
});
// Load default fragment
changeFragment(new HomeFragment(), false);
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
View headerLayout = navigationView.getHeaderView(0);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(this);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
Toast.makeText(this, "Back pressed", Toast.LENGTH_SHORT)
.show();
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START))
drawer.closeDrawer(GravityCompat.START);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
super.onBackPressed();
}
}
private void changeFragment(Fragment fm, boolean addToBackStack)
{
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.replace(R.id.frame_layout_content, fm);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if (addToBackStack) ft.addToBackStack(null);
ft.commit();
}
}
And how I change (replace) fragments from HomeFragment:
IndexDetailFragment newFragment = new IndexDetailFragment();
Bundle args = new Bundle();
args.putString(IndexDetailFragment.ARG_INDEX_ID, id);
newFragment.setArguments(args);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
transaction.replace(R.id.frame_layout_content, newFragment);
transaction.addToBackStack(null);
transaction.commit();
setNavigationOnClick() on the toolbar after setSupportActionBar(toolbar) :
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Toast.makeText(getActivity(), "Back clicked!",
Toast.LENGTH_SHORT).show();
}
});
I have made a small app for reference
FirstFragment
public class FirstFragment extends Fragment {
public FirstFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
SecondFragment
public class SecondFragment extends Fragment {
public SecondFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_second, container, false);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private Toolbar mToolbar;
private ActionBarDrawerToggle drawerToggle;
private DrawerLayout mDrawerLayout;
private String TAG = "MainActivity";
private FragmentManager mFragmentManager;
private NavigationView mNavigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mToolbar != null) {
setSupportActionBar(mToolbar);
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer);
drawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};
mDrawerLayout.addDrawerListener(drawerToggle);
mNavigationView = findViewById(R.id.navigation);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.first:
changeFragment(new FirstFragment(), true);
return true;
case R.id.second:
changeFragment(new SecondFragment(), true);
return true;
}
return false;
}
});
mFragmentManager = getSupportFragmentManager();
changeFragment(new FirstFragment(), true);
}
#Override
protected void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if (drawerToggle != null) {
drawerToggle.syncState();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
Log.i(TAG, "onOptionsItemSelected: Home Button Clicked");
if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawer(Gravity.START);
} else {
mDrawerLayout.openDrawer(Gravity.START);
}
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawer(Gravity.START);
}
if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawer(Gravity.START);
} else if (mFragmentManager.getBackStackEntryCount() > 0) {
mFragmentManager.popBackStack();
} else {
super.onBackPressed();
}
}
private void changeFragment(Fragment fragment, boolean needToAddBackstack) {
FragmentTransaction mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.replace(R.id.FRAME_CONTENT, fragment);
mFragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if (needToAddBackstack)
mFragmentTransaction.addToBackStack(null);
mFragmentTransaction.commit();
}
}
activity_main
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/abc_action_bar_default_height_material"
android:background="#color/colorPrimaryDark"
/>
<FrameLayout
android:id="#+id/FRAME_CONTENT"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/abc_action_bar_default_height_material" />
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_marginTop="#dimen/abc_action_bar_default_height_material"
app:menu="#menu/drawermenu" />
</android.support.v4.widget.DrawerLayout>
I had the same issue.
I finally solved by adding this in the onCreate method.
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() == 0){
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
menuToggle.setDrawerIndicatorEnabled(true);
}else{
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
menuToggle.setDrawerIndicatorEnabled(false);
}
}
});
Hope it helps
Simplest solution for Kotlin Developers
Just add this in your root activity where fragments resist
if (supportFragmentManager.backStackEntryCount > 0) {
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
toolbar.setNavigationOnClickListener {
if (supportFragmentManager.backStackEntryCount > 0) {
super.onBackPressed()
} else {
supportActionBar!!.setDisplayHomeAsUpEnabled(false)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
drawerLayout.openDrawer(GravityCompat.START)
}
}
} else {
supportActionBar!!.setDisplayHomeAsUpEnabled(false)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
}
Here, whenever setDisplayHomeAsUpEnabled is set true , I am showing back button. and on cliking it, I am calling super.onBackPressed() which is similar to what your back button does!
Add below code in onCreate() method
that's work for me
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, " Back Pressed ", Toast.LENGTH_SHORT).show();
}
});
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
drawerToggle = new ActionBarDrawerToggle(MainActivity.this, drawerLayout, toolbar,
R.string.app_name, R.string.app_name);
drawerLayout.addDrawerListener(drawerToggle);
drawerToggle.syncState();
}
}
});
The thing that solved me the issue was this:
I used the code that came automatically with the NavigationDrawerActivity template, and it was something like this:
NavigationView navigationView = _binding.navView;
// Passing each menu ID as a set of Ids because each menu should be considered as top level destinations:
_AppBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_x, R.id.nav_y, R.id.nav_z)
.setOpenableLayout(_binding.drawerLayout)
.build();
_navController = Navigation.findNavController(this, R.id.nav_host_content_main);
NavigationUI.setupActionBarWithNavController(this, _navController, _AppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, _navController);
And I struggled a lot with many tricks and hacks, and nothing was working for me.
At some point, I have noticed that the fragments that I want to enable the back button are "being considered as top level destinations", exactly what the comment says in the code above. Then I removed those sub-fragments and BOOM that was it, with not a single hack or line of code needed, this is provided out of the box, I just needed to pay attention to it.
So in my case, I changed to the below code:
NavigationView navigationView = _binding.navView;
// Passing each menu ID as a set of Ids because each menu should be considered as top level destinations:
_AppBarConfiguration = new AppBarConfiguration.Builder(R.id.nav_x)
.setOpenableLayout(_binding.drawerLayout)
.build();
_navController = Navigation.findNavController(this, R.id.nav_host_content_main);
NavigationUI.setupActionBarWithNavController(this, _navController, _AppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, _navController);
: Just removed R.id.nav_y, R.id.nav_z in the AppBarConfiguration
I struggled with this for a while. I got it to work by:
setting my the drawer layout in MainActivity.kt:
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
findViewById<NavigationView>(R.id.nav_view).setupWithNavController(navController)
appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
Include the toolbar layout in each of the fragments that I need the Toolbar:
<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:fitsSystemWindows="true"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
/>
</com.google.android.material.appbar.AppBarLayout>
</LinearLayout>
Add the following code to the home fragment of the drawer, the one from which other fragments are called using the drawer. This gets the hamburguer icon to work, onside the onViewCreated method:
var myToolbar = requireActivity()
.findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
myToolbar.inflateMenu(R.menu.menu)
val drawerLayout = requireActivity().findViewById<DrawerLayout>(R.id.drawer_layout)
val toggle = ActionBarDrawerToggle(
activity, drawerLayout, myToolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close
)
toggle.setDrawerIndicatorEnabled(true)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
Add the following code in the kotlin code for the fragments that are after the home fragment, this will get the back arrow:
val navController = findNavController()
val appBarConfiguration = AppBarConfiguration(navController.graph)
view.findViewById<Toolbar>(R.id.toolbar)
.setupWithNavController(navController, appBarConfiguration)
In the destination fragment add the following code in onCreateView Method:
activity?.onBackPressedDispatcher?.addCallback(
viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
findNavController().navigate(
[back fragment directions] )
}
})
Hope this helps everyone struggling with this :)
I am developing an Android app about music. In this app, I have two fragments: PopFragment e GenresFragment.
In the XML file of PopFragment called fragment_pop.xml, I have toolbar with a back arrow that goes back to GenresFragment.
My toolbar code is this:
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<include
android:layout_height="wrap_content"
android:layout_width="match_parent"
layout="#layout/toolbar_layout"
/>
</android.support.design.widget.AppBarLayout>
<ImageButton
android:id="#+id/arrowPop"
android:layout_width="54dp"
android:layout_height="wrap_content"
android:src="#drawable/ic_arrow_back_black_24dp"
style="?android:attr/borderlessButtonStyle"
/>
In the Java file of PopFragment called PopActivity, I have some code but it's not working.
I have this code:
public class PopActivity extends AppCompatActivity implements View.OnClickListener {
public PopActivity() {
// Required empty public constructor
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_pop);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
ImageButton backBtn = (ImageButton)findViewById(R.id.arrowPop);
}
#Override
public void onClick (View view) {
Intent i = new Intent();
switch (view.getId()) {
case R.id.arrowPop:
break;
}
}
Can you help me please?
Thank you
Try something like:
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
inflater.inflate(R.menu.your_menu, menu);
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
getActivity().onBackPressed();
break;
}
}
return true;
}
You generally don't need to add your own arrow icon, the Toolbar should be able to handle it for you.
if(shouldShowArrow()) {
drawerLayout.setDrawerLockMode(LOCK_MODE_LOCKED_CLOSED, GravityCompat.START);
drawerToggle.setDrawerIndicatorEnabled(false);
MyActivity.this.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else { // hamburglar icon
drawerLayout.setDrawerLockMode(LOCK_MODE_UNLOCKED, GravityCompat.START);
MyActivity.this.getSupportActionBar().setDisplayHomeAsUpEnabled(false);
drawerToggle.setDrawerIndicatorEnabled(true);
}
drawerToggle.syncState();
And then you can define what happens when you click the arrow
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
drawerToggle = new ActionBarDrawerToggle(MyActivity.this, drawerLayout, toolbar, R.string.open, R.string.close) {
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
MyActivity.this.supportInvalidateOptionsMenu();
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
MyActivity.this.supportInvalidateOptionsMenu();
}
};
drawerLayout.setDrawerListener(drawerToggle);
drawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// what to do when you click the arrow
}
});
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setHomeButtonEnabled(true);
}
#Override
protected void onPostCreate(Bundle bundle) {
super.onPostCreate(bundle);
drawerToggle.syncState();
}
#Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
Use the following code as a quick fix, which mimics the back button being pressed.
switch (view.getId()) {
case R.id.arrowPop:
onBackPressed();
break;
}
Using this code, you shouldn't have to define the back button in the toolbar yourself, Android will handle it.
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
Then when you click the back button, Android will call onBackPressed() for you.
My BaseDrawerActivity extends BaseActivity and I have a Toolbar in BaseActivity.
The toolbar shows with no issues in classes that extend BaseActivity, but ALL classes that extend BaseDrawerActivity just show a blank toolbar. The nav drawer works fine.
When I had one main activity class (BaseActivity + BaseDrawerActivity) the toolbar showed no problem and the nav drawer worked.
Why is my implementation here not showing the Toolbar? I debugged and getToolbar() is returning the toolbar for sure.
activity_base_drawer.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar"/>
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:windowContentOverlay">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<include layout="#layout/call_to_action_banner"/>
</FrameLayout>
<ListView
android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
style="#style/NavDrawerListView" />
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="#style/ToolbarOverlay"
android:popupTheme="#style/ToolbarOverlay"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:minHeight="?attr/actionBarSize"
android:elevation="10dp"/>
BaseDrawerActivity
public abstract class BaseDrawerActivity extends BaseActivity {
private static final int LAYOUT_ID = R.layout.activity_base_drawer;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private NavDrawerAdapter mNavDrawerAdapter;
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)){
mDrawerLayout.closeDrawers();
} else {
super.onBackPressed();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(LAYOUT_ID);
setupNavDrawer();
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
private void setupNavDrawer() {
final ListView navDrawerListView = (ListView) findViewById(R.id.navigation_drawer);
View header = getLayoutInflater().inflate(R.layout.nav_drawer_header, null, false);
mNavDrawerAvatarImageView = (ImageView) header.findViewById(R.id.avatar);
mNavDrawerUsernameTextView = (CustomTextView) header.findViewById(R.id.username);
navDrawerListView.addHeaderView(header);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
getToolbar(),
R.string.navigation_drawer_open,
R.string.navigation_drawer_close) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
updateNavDrawerUserInfo();
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mNavDrawerAdapter = new NavDrawerAdapter(this);
navDrawerListView.setAdapter(mNavDrawerAdapter);
navDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
mDrawerLayout.closeDrawer(GravityCompat.START);
onNavigationDrawerItemSelected(position);
}
});
updateNavDrawerUserInfo();
}
private void updateNavDrawerUserInfo() {
final DatabaseHelper db = DatabaseHelper.getInstance(this);
if (db.doesUserExist(SharedPrefs.getUserId())) {
final User currentUser = db.getUser(SharedPrefs.getUserId());
if (currentUser != null) {
if (currentUser.getAvatarType() != null) {
try {
mNavDrawerAvatarImageView.setImageDrawable(getResources().getDrawable(
ViewUtil.getAvatarHeadDrawableId(this,
currentUser.getAvatarType())));
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
}
if (currentUser.getUsername() != null) {
mNavDrawerUsernameTextView.setText(currentUser.getUsername());
}
}
}
}
}
BaseActivity
private void setupToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle("");
getSupportActionBar().setSubtitle("");
getSupportActionBar().setLogo(R.drawable.logo_toolbar);
}
mUpdatingSpinner = (ProgressBar) getLayoutInflater().inflate(
R.layout.toolbar_updating_spinner, null, false);
int dpInPixels = (int) getResources().getDimension(R.dimen.toolbar_updating_spinner);
Toolbar.LayoutParams spinnerLp = new Toolbar.LayoutParams(dpInPixels, dpInPixels,
Gravity.END);
mToolbar.addView(mUpdatingSpinner, spinnerLp);
}
I found the answer although I don't fully understand it.
I basically called setupToolbar() again in my BaseDrawerActivity right before I call setupNavDrawer() and for some reason this fixed it.
I think the reference to the Toolbar from BaseActivity wasn't retrieving correctly (even though I debugged and it had a reference to it). Another thing I tried is setSupportActionBar(mToolbar) right before setting up the nav drawer but that didn't work.
If anyone has any ideas as to why I have to setup the toolbar again in order for it to show I'd be glad to hear it!
go to the AndroidManifest.xml file and replace
android:theme="#style/AppTheme"
with
android:theme="#android:style/Theme.Holo.Light.DarkActionBar"
you have to use setSupportActionBar(Toolbar toolbar).
This question should help.
I want to show Home (Hamburger) button by default when I open MyActivity. Unfortunately I don't see any buttons in the left top corner. But Home button appears after I open and close my Drawer.
I use the latest appcompat-v7:23.0.1 library:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
}
My activity:
public class MyActivity extends AppCompatActivity{
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mTitle;
private Toolbar toolbar;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer);
toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
}
mTitle = getTitle();
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
toolbar,
R.string.hello_world,
R.string.app_name)
{
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
toolbar.setTitle(mTitle);
invalidateOptionsMenu();
syncState();
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
//toolbar.setTitle(mDrawerTitle);
invalidateOptionsMenu();
syncState();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
}
activity_drawer.xml:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
style="#style/MatchParent">
<!-- Your normal content view -->
<LinearLayout
style="#style/MatchParent"
android:orientation="vertical">
<include layout="#layout/toolbar"/>
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<FrameLayout
android:layout_width="304dp"
android:layout_height="match_parent"
android:layout_gravity="left|start">
<include layout="#layout/navigation_drawer" />
</FrameLayout>
</android.support.v4.widget.DrawerLayout>
I've tried the following variant to show Home button by default:
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
But it doesn't work also.
For example, if I set only:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
then Up (arrow) button shows correctly when I open activity and transform to the Home button after I open and close my Drawer.
What could be the problem?
Thanks in advance.
If you aren't calling syncState from your Activity's onPostCreate or not calling through to onConfigurationChanged or onOptionsItemSelected corresponding to your Activity callbacks, you should do.
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
Im using Android Studio 1.2
The icon drawer in actionbar is give me an error when I click then but is work fine If I open it sliding with the hand from the left to the rigth.
this is my layout where I have my drawer list from the left; the list of options is in listView "mimenu"
<RelativeLayout xmlns:android="xxxxxx"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:background="#ffffff"
tools:context="xxxx">
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffffff">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<ListView
android:id="#+id/listaxx"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
></ListView>
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_gravity="left"
>
<ListView
android:id="#+id/mimenu"
android:layout_width="match_parent"
android:layout_below="#+id/profileBox"
android:choiceMode="singleChoice"
android:layout_height="match_parent"
android:background="#ffffff"
android:divider="#eee"
android:dividerHeight="1dp"
/>
</RelativeLayout>
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
In my class java
public class ListaPat extends Activity {
public ArrayList<Pat> lstPat= new ArrayList<Pat>();
private Pat_Adaptador adaptador;
private LinearLayout linearLayout;
ArrayAdapter<CharSequence> navigationDrawerAdapter;
ListView leftDrawerList;
String[] leftSliderData = new String[]{"test1","test2"};
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lista_patx);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
leftDrawerList = (ListView)findViewById(R.id.mimenu);
navigationDrawerAdapter= new ArrayAdapter<CharSequence>( ListaPat .this, android.R.layout.simple_list_item_1, leftSliderData);
leftDrawerList.setAdapter(navigationDrawerAdapter);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
RellenarNoticias();
InicializarLista();
mDrawerLayout.setDrawerListener(mDrawerToggle);
getActionBar().setDisplayShowHomeEnabled(true);
getActionBar().setHomeButtonEnabled(true);
mDrawerToggle.syncState();
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if(mDrawerLayout.isDrawerOpen(leftDrawerList)) {
mDrawerLayout.closeDrawer(leftDrawerList);
}
else {
mDrawerLayout.openDrawer(leftDrawerList);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
You need to extend either ActionbarActivity, or AppCompatActivity, and use a Toolbar widget to be in the beginning of your Activity. In your activities on create, do the following:
public class YourActivity extends ActionBarActivity{
...
...
private Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
//Set toggle with toolbar now!
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
mToolbar,
R.string.drawer_open,
R.string.drawer_close) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
And for your Toolbar that lives in your activity xml (the very first element for your layout!)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:background="#color/primary_color"
android:title="#string/app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:theme="CreateSomeStyleHereIfYouNeed"
app:popupTheme="#android:style/Theme.Holo.Light"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
</android.support.v7.widget.Toolbar>
I fix the problem changing this function
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if(mDrawerLayout.isDrawerOpen(leftDrawerList)) {
mDrawerLayout.closeDrawer(leftDrawerList);
}
else {
mDrawerLayout.openDrawer(leftDrawerList);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
New function that fix the problem
#Override public boolean onOptionsItemSelected(MenuItem item) {if (mDrawerToggle.onOptionsItemSelected(item)){ return true; } return super.onOptionsItemSelected(item); }