Android navigation drawer toggle icon to right
There's really no (practical) way to make ActionBarDrawerToggle
do that, as it is always set on the start/left-side navigation button. However, that class is basically just a DrawerListener
that manages a specialized Drawable
, and wires an ImageButton
to the DrawerLayout
. We can put together something similar for an end/right-side drawer with an ImageButton
that we can place on that same side in a Toolbar
(which is required for this example).
public class EndDrawerToggle implements DrawerLayout.DrawerListener {
private final DrawerLayout drawerLayout;
private final AppCompatImageButton toggleButton;
private final int openDrawerContentDescRes;
private final int closeDrawerContentDescRes;
private DrawerArrowDrawable arrowDrawable;
public EndDrawerToggle(DrawerLayout drawerLayout, Toolbar toolbar,
int openDrawerContentDescRes, int closeDrawerContentDescRes) {
this.drawerLayout = drawerLayout;
this.openDrawerContentDescRes = openDrawerContentDescRes;
this.closeDrawerContentDescRes = closeDrawerContentDescRes;
toggleButton = new AppCompatImageButton(toolbar.getContext(), null,
R.attr.toolbarNavigationButtonStyle);
toolbar.addView(toggleButton, new Toolbar.LayoutParams(GravityCompat.END));
toggleButton.setOnClickListener(v -> toggle());
loadDrawerArrowDrawable();
}
public void syncState() {
if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
setPosition(1f);
} else {
setPosition(0f);
}
}
public void onConfigurationChanged(Configuration newConfig) {
loadDrawerArrowDrawable();
syncState();
}
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
setPosition(Math.min(1f, Math.max(0f, slideOffset)));
}
@Override
public void onDrawerOpened(@NonNull View drawerView) {
setPosition(1f);
}
@Override
public void onDrawerClosed(@NonNull View drawerView) {
setPosition(0f);
}
@Override
public void onDrawerStateChanged(int newState) {}
private void loadDrawerArrowDrawable() {
arrowDrawable = new DrawerArrowDrawable(toggleButton.getContext());
arrowDrawable.setDirection(DrawerArrowDrawable.ARROW_DIRECTION_END);
toggleButton.setImageDrawable(arrowDrawable);
}
private void toggle() {
final int drawerLockMode = drawerLayout.getDrawerLockMode(GravityCompat.END);
if (drawerLayout.isDrawerVisible(GravityCompat.END)
&& (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
drawerLayout.closeDrawer(GravityCompat.END);
} else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
drawerLayout.openDrawer(GravityCompat.END);
}
}
private void setPosition(float position) {
if (position == 1f) {
arrowDrawable.setVerticalMirror(true);
setContentDescription(closeDrawerContentDescRes);
} else if (position == 0f) {
arrowDrawable.setVerticalMirror(false);
setContentDescription(openDrawerContentDescRes);
}
arrowDrawable.setProgress(position);
}
private void setContentDescription(int resId) {
toggleButton.setContentDescription(toggleButton.getContext().getText(resId));
}
}
The EndDrawerToggle
class works exactly the same way as ActionBarDrawerToggle
does when used with a Toolbar
(except the constructor call doesn't need an Activity
argument): first instantiate the toggle, then add it as a DrawerListener
, and sync it in the Activity
's onPostCreate()
method. If you're already overriding the Activity
's onConfigurationChanged()
method, you'll want to call the toggle's corresponding method there, like you would for an ActionBarDrawerToggle
.
private EndDrawerToggle drawerToggle;
public void initNavigationDrawer() {
...
drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
drawerToggle = new EndDrawerToggle(drawerLayout,
toolbar,
R.string.drawer_open,
R.string.drawer_close);
drawerLayout.addDrawerListener(drawerToggle);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
If you have two drawers and need to use ActionBarDrawerToggle
and EndDrawerToggle
simultaneously, it is possible, but we'll need to handle intercepting and dispatching drawer motion events to the correct toggle.
If you prefer fewer classes, you could subclass ActionBarDrawerToggle
and merge EndDrawerToggle
's functionality into it, dispatching each DrawerListener
method call either to the super
class, or to the local end toggle code.
However, composition is arguably much cleaner here, and it will let us use EndDrawerToggle
as is. This example is a DrawerListener
that relays syncState()
and onConfigurationChanged()
calls to each toggle, but dispatches the listener method calls only to the appropriate one, depending on which drawer is moving.
public class DualDrawerToggle implements DrawerLayout.DrawerListener {
private final DrawerLayout drawerLayout;
private final Toolbar toolbar;
private final ActionBarDrawerToggle actionBarDrawerToggle;
private final EndDrawerToggle endDrawerToggle;
public DualDrawerToggle(Activity activity, DrawerLayout drawerLayout, Toolbar toolbar,
int startDrawerOpenContDescRes, int startDrawerCloseContDescRes,
int endDrawerOpenContDescRes, int endDrawerCloseContDescRes) {
this.drawerLayout = drawerLayout;
this.toolbar = toolbar;
this.actionBarDrawerToggle =
new ActionBarDrawerToggle(activity, drawerLayout, toolbar,
startDrawerOpenContDescRes, startDrawerCloseContDescRes);
this.endDrawerToggle =
new EndDrawerToggle(drawerLayout, toolbar,
endDrawerOpenContDescRes, endDrawerCloseContDescRes);
}
public void syncState() {
actionBarDrawerToggle.syncState();
endDrawerToggle.syncState();
}
public void onConfigurationChanged(Configuration newConfig) {
actionBarDrawerToggle.onConfigurationChanged(newConfig);
// Fixes bug in ABDT, which only reloads the up nav indicator, for some reason.
final DrawerArrowDrawable dad = new DrawerArrowDrawable(toolbar.getContext());
actionBarDrawerToggle.setDrawerArrowDrawable(dad);
endDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerSlide(drawerView, slideOffset);
} else {
endDrawerToggle.onDrawerSlide(drawerView, slideOffset);
}
}
@Override
public void onDrawerOpened(@NonNull View drawerView) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerOpened(drawerView);
} else {
endDrawerToggle.onDrawerOpened(drawerView);
}
}
@Override
public void onDrawerClosed(@NonNull View drawerView) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerClosed(drawerView);
} else {
endDrawerToggle.onDrawerClosed(drawerView);
}
}
@Override
public void onDrawerStateChanged(int newState) {}
@SuppressLint("RtlHardcoded")
static boolean isStartDrawerView(View drawerView, int layoutDirection) {
final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
final int horizontalGravity = gravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK;
if ((horizontalGravity & GravityCompat.RELATIVE_LAYOUT_DIRECTION) > 0) {
return horizontalGravity == GravityCompat.START;
} else {
if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
return horizontalGravity == Gravity.RIGHT;
} else {
return horizontalGravity == Gravity.LEFT;
}
}
}
}
Again, DualDrawerToggle
works exactly the same way as ActionBarDrawerToggle
does when used with a Toolbar
, except for the extra content description resource IDs in the constructor.
Do note that the one DualDrawerToggle
creates and manages both other toggles internally. You don't need to set up any other toggle instances in your Activity
; just the DualDrawerToggle
.
Notes:
If you read through the code, you'll see that
EndDrawerToggle
– and therefore alsoDualDrawerToggle
– can be readily adapted to put a toggle on pretty much anything that can display aDrawable
and register clicks; e.g., aFloatingActionButton
, an options menu item, aTextView
's compound drawable, etc. Simply replace theAppCompatImageButton
with your target UI component, which can be passed in the constructor in place of theToolbar
, since the toggle won't be added to that anymore.Additionally, this could be modified to work with the start/left-aligned drawer, too – completely replacing
ActionBarDrawerToggle
– so that its toggle could be placed on those various components, as well.The
AppCompatImageButton
used here is a regular child of theToolbar
. If you're using a menu on theToolbar
, that menu will take precedence in the layout, and push the toggle inward. To keep it on the outside, you can modify the class as described above to set the toggle on an action menu item. I've an example of that in my answer here.That menu item example might also be useful if your design requires you use the decor-supplied
ActionBar
in lieu of your ownToolbar
. ThoughActionBarDrawerToggle
can work with a decor-suppliedActionBar
, this example can not, as is.
how to set Drawer Layout icon in right side of the device screen?
This icon represents navigation menu, which by design has to be on left side of the screen. As per the guidelines, we can although have a navigation drawer on right side, but that shall be used to modify the contents (for example filters). For all such purposes you might want to use ActionbarItem, and put up an ActionItem in right corner of the screen. Click on that action item will open or close the right navigation drawer.
But for sure, as per the design, this animated three lined menu icon, which represents navigation shall be on left hand side.
Just for the information, to put the navigation drawer on right side, you have to change the gravity of navigation drawer as follows:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_background" >
<!-- The main content view -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
<!-- The navigation drawer -->
<LinearLayout
android:id="@+id/right_drawer"
android:layout_width="280dp"
android:layout_gravity="end"
android:layout_height="match_parent"
android:orientation="vertical" />
</android.support.v4.widget.DrawerLayout>
Also, in this case you really really want the navigation menu icon, on right either use custom header layouts or a library like ActionBarSherlock to edit it.
I hope this helps!
Navigation Drawer Toggle Icon without toolbar
What you see as "nav drawer toggle icon" is actually an ActionBarDrawerToggle
object and as its name suggests it can only reside in a Toolbar.
The "3 dotted icon" is the toolbar's menu button. You can create a new button with the same icon and use it to popup a menu but it's not that simple.
Remember that the Toolbar is a container and you can customize it the way you want, so my advice is to use it because the other option is a lot harder.
You can set:
in xml
android:elevation="0dp"
or
app:elevation="0dp"
or bycode
getActionBar().setElevation(0);
to remove any elevation of the toolbar.
ActionBar Navigation Drawer icon on the Right side
This is how I've implemented the right navigation drawer. Just need to open and close the drawer based on Gravity. In this example they use Gravity.RIGHT
, I use Gravity.END
. I'm not sure which one is right or wrong. Hope this helps.
This link for ActionBar animation provides some good information, and should give a good base for doing the navigation drawer icon animation.
Change Icon Of Navigation Drawer
Here is the sample code taken from
Creating a Navigation Drawer
Activity.class
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
...
public void onCreate(Bundle savedInstanceState) {
...
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description */
R.string.drawer_close /* "close drawer" description */
) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getActionBar().setTitle(mTitle);
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActionBar().setTitle(mDrawerTitle);
}
};
// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
}
@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);
}
...
}
Related Topics
How to Change the Textcolor on an Android Searchview
How to Find If a Particular Package Exists on My Android Device
Connecting Mongodb from Mobile or Browser Based Application
Android Getlastknownlocation Returns Null
Intel's Haxm Equivalent for Amd on Windows Os
Failed to Resolve: Com.Android.Support:Appcompat-V7:27.+ (Dependency Error)
How to Create a Circular (Endless) Recyclerview
Is There a Listener for When the Webview Displays It's Content
How to Retrieve Style Attributes Programmatically from Styles.Xml
Android Gettext from Edittext Field
How to Group Radiobutton from Different Linearlayouts
Error: "Adb Connection Error:An Existing Connection Was Forcibly Closed by the Remote Host"
Android, How to Apply CSS into Webview
What Does This Google Play APK Publish Error Message Mean
Android Firebase Dynamitemodule: Failed to Load Module Descriptor