Android Navigation Drawer Toggle Icon to Right

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 also DualDrawerToggle – can be readily adapted to put a toggle on pretty much anything that can display a Drawable and register clicks; e.g., a FloatingActionButton, an options menu item, a TextView's compound drawable, etc. Simply replace the AppCompatImageButton with your target UI component, which can be passed in the constructor in place of the Toolbar, 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 the Toolbar. If you're using a menu on the Toolbar, 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 own Toolbar. Though ActionBarDrawerToggle can work with a decor-supplied ActionBar, 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



Leave a reply



Submit