How to implement DrawerArrowToggle from Android appcompat v7 21 library
Solution 1
First, you should know now the android.support.v4.app.ActionBarDrawerToggle
is deprecated.
You must replace that with android.support.v7.app.ActionBarDrawerToggle
.
Here is my example and I use the new Toolbar
to replace the ActionBar
.
MainActivity.java
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(
this, mDrawerLayout, mToolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close
);
mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
mDrawerToggle.syncState();
}
styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
</style>
<style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
<item name="spinBars">true</item>
<item name="color">@android:color/white</item>
</style>
You can read the documents on AndroidDocument#DrawerArrowToggle_spinBars
This attribute is the key to implement the menu-to-arrow animation.
public static int DrawerArrowToggle_spinBars
Whether bars should rotate or not during transition
Must be a boolean value, either "true" or "false".
So, you set this: <item name="spinBars">true</item>
.
Then the animation can be presented.
Hope this can help you.
Solution 2
If you are using the Support Library provided DrawerLayout as suggested in the Creating a navigation drawer training, you can use the newly added android.support.v7.app.ActionBarDrawerToggle (note: different from the now deprecated android.support.v4.app.ActionBarDrawerToggle):
shows a Hamburger icon when drawer is closed and an arrow when drawer is open. It animates between these two states as the drawer opens.
While the training hasn't been updated to take the deprecation/new class into account, you should be able to use it almost exactly the same code - the only difference in implementing it is the constructor.
Solution 3
I created a small application which had similar functionality
MainActivity
public class MyActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(
this,
drawerLayout,
toolbar,
R.string.open,
R.string.close
)
{
public void onDrawerClosed(View view)
{
super.onDrawerClosed(view);
invalidateOptionsMenu();
syncState();
}
public void onDrawerOpened(View drawerView)
{
super.onDrawerOpened(drawerView);
invalidateOptionsMenu();
syncState();
}
};
drawerLayout.setDrawerListener(actionBarDrawerToggle);
//Set the custom toolbar
if (toolbar != null){
setSupportActionBar(toolbar);
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
actionBarDrawerToggle.syncState();
}
}
My XML of that Activity
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyActivity"
android:id="@+id/drawer"
>
<!-- The main content view -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include layout="@layout/toolbar_custom"/>
</FrameLayout>
<!-- The navigation drawer -->
<ListView
android:layout_marginTop="?attr/actionBarSize"
android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:background="#457C50"/>
</android.support.v4.widget.DrawerLayout>
My Custom Toolbar XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/toolbar"
android:background="?attr/colorPrimaryDark">
<TextView android:text="U titel"
android:textAppearance="@android:style/TextAppearance.Theme"
android:textColor="@android:color/white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</android.support.v7.widget.Toolbar>
My Theme Style
<resources>
<style name="AppTheme" parent="Base.Theme.AppCompat"/>
<style name="AppTheme.Base" parent="Theme.AppCompat">
<item name="colorPrimary">@color/primary</item>
<item name="colorPrimaryDark">@color/primaryDarker</item>
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
</style>
<style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
<item name="spinBars">true</item>
<item name="color">@android:color/white</item>
</style>
<color name="primary">#457C50</color>
<color name="primaryDarker">#580C0C</color>
</resources>
My Styles in values-v21
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>
</resources>
Solution 4
To answer the updated part of your question: to style the drawer icon/arrow, you have two options:
Style the arrow itself
To do this, override drawerArrowStyle
in your theme like so:
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
<item name="drawerArrowStyle">@style/MyTheme.DrawerArrowToggle</item>
</style>
<style name="MyTheme.DrawerArrowToggle" parent="Widget.AppCompat.DrawerArrowToggle">
<item name="color">@android:color/holo_purple</item>
<!-- ^ this will make the icon purple -->
</style>
This is probably not what you want, because the ActionBar itself should have consistent styling with the arrow, so, most probably, you want the option two:
Theme the ActionBar/Toolbar
Override the android:actionBarTheme
(actionBarTheme
for appcompat) attribute of the global application theme with your own theme (which you probably should derive from ThemeOverlay.Material.ActionBar/ThemeOverlay.AppCompat.ActionBar
) like so:
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
<item name="actionBarTheme">@style/MyTheme.ActionBar</item>
</style>
<style name="MyTheme.ActionBar" parent="ThemeOverlay.AppCompat.ActionBar">
<item name="android:textColorPrimary">@android:color/white</item>
<!-- ^ this will make text and arrow white -->
<!-- you can also override drawerArrowStyle here -->
</style>
An important note here is that when using a custom layout with a Toolbar
instead of stock ActionBar implementation (e.g. if you're using the DrawerLayout
-NavigationView
-Toolbar
combo to achieve the Material-style drawer effect where it's visible under translucent statusbar), the actionBarTheme
attribute is obviosly not picked up automatically (because it's meant to be taken care of by the AppCompatActivity
for the default ActionBar
), so for your custom Toolbar
don't forget to apply your theme manually:
<!--inside your custom layout with DrawerLayout
and NavigationView or whatever -->
<android.support.v7.widget.Toolbar
...
app:theme="?actionBarTheme">
-- this will resolve to either AppCompat's default ThemeOverlay.AppCompat.ActionBar
or your override if you set the attribute in your derived theme.
PS a little comment about the drawerArrowStyle
override and the spinBars
attribute -- which a lot of sources suggest should be set to true
to get the drawer/arrow animation. Thing is, spinBars
it is true
by default in AppCompat (check out the Base.Widget.AppCompat.DrawerArrowToggle.Common
style), you don't have to override actionBarTheme
at all to get the animation working. You get the animation even if you do override it and set the attribute to false
, it's just a different, less twirly animation. The important thing here is to use ActionBarDrawerToggle
, it's what pulls in the fancy animated drawable.
Solution 5
I want to correct little bit the above code
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(
this, mDrawerLayout, mToolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close
);
mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
and all the other things will remain same...
For those who are having problem Drawerlayout
overlaying toolbar
add android:layout_marginTop="?attr/actionBarSize"
to root layout of drawer content
BigDX
Updated on September 09, 2020Comments
-
BigDX over 3 years
So now that Android 5.0 was released i was wondering how to implement the animated actionbar icons.
This library here implements it fine for me but since the appcompat v7 library has it how can it be implemented?
The library references it in themes.xml
<item name="drawerArrowStyle">@style/Widget.AppCompat.DrawerArrowToggle</item>
Under this style
<style name="Base.V7.Theme.AppCompat" parent="Platform.AppCompat">
UPDATE
I got this implemented using the v7 DrawerToggle. However I cannot style it. Please Help
I found the styling for it in the v7 styles_base.xml
<style name="Base.Widget.AppCompat.DrawerArrowToggle" parent=""> <item name="color">?android:attr/textColorSecondary</item> <item name="thickness">2dp</item> <item name="barSize">18dp</item> <item name="gapBetweenBars">3dp</item> <item name="topBottomBarArrowSize">11.31dp</item> <item name="middleBarArrowSize">16dp</item> <item name="drawableSize">24dp</item> <item name="spinBars">true</item> </style>
I added this to my styles and did not work. Also added to my attr.xml
<declare-styleable name="DrawerArrowToggle"> <!-- The drawing color for the bars --> <attr name="color" format="color"/> <!-- Whether bars should rotate or not during transition --> <attr name="spinBars" format="boolean"/> <!-- The total size of the drawable --> <attr name="drawableSize" format="dimension"/> <!-- The max gap between the bars when they are parallel to each other --> <attr name="gapBetweenBars" format="dimension"/> <!-- The size of the top and bottom bars when they merge to the middle bar to form an arrow --> <attr name="topBottomBarArrowSize" format="dimension"/> <!-- The size of the middle bar when top and bottom bars merge into middle bar to form an arrow --> <attr name="middleBarArrowSize" format="dimension"/> <!-- The size of the bars when they are parallel to each other --> <attr name="barSize" format="dimension"/> <!-- The thickness (stroke size) for the bar paint --> <attr name="thickness" format="dimension"/> </declare-styleable>
But crashes and says color type error when doing so. What am i missing?
-
BigDX over 9 yearsI am using v4 in my app bc i do not need to support devices prior to api 15. So if i wanted this to work i would have to use the v7 actionbar drawer toggle? If i did that wouldn't I have to convert all my styles to AppCompat and fragment activities to actionbar activities and so on? Or can I implement just the Drawer toggle from v7. Right now I use v7 for card views. Should I even be using v4 if im not supporting api below 15? And I guess I need v7 for the card views.
-
ianhanniballake over 9 yearsAll of the Support Library compatibility for Material design is implemented in v7-appcompat and is recommended if you want to support that styling on <5.0 devices. AppCompat is built off of and requires v4 so it really up to if you want to use AppCompat at all. If you're already using FragmentActivity, you're already pretty close - the difference in styling is pretty small now (mostly just replacing the android: attributes with non-namespaced attributes).
-
BigDX over 9 yearsUpdated the question if you wouldn't mind taking a look please
-
ianhanniballake over 9 yearsThat's really a whole separate question on styling. I'd suggest submitting that part as a whole other question (feel free to add a comment with a link to it).
-
BigDX over 9 years
-
mikepenz over 9 yearsjust tried this. but it won't show the DrawerArrowToggle icon for me. Any ideas?
-
Nitin Misra over 9 yearsme also, doesn't show toggle icon, any help appreciated
-
Igoussam over 9 yearsI have updated the code with the fix from @NitinMisra's answer.
-
BamsBamx over 9 yearsWith this code the Toolbar gets under the shadow when the navigation drawer is opened. Is this the way its supposed to work?
-
Yong over 9 years@BamsBamx the Toolbar under the shadow might be result to your layout resouce file. Your Toolbar item might be included in the DrawerLayout so that your Toolbar got under the shadow.
-
BamsBamx over 9 years@Yong Thanks for the answer. In this case please, could you post an example for the layout? I tried to make a LinearLayout(vertical) with Toolbar(wrap_content) and NavDrawer(weight 1) but, in this case, the NavDrawer wont open if I swipe from the left to the right
-
mraviator over 9 yearsI'm confused about one thing. If my minSdkVersion is 21 (why not...), do I even need to mess with support libraries for the latest Material Design look nav drawer with hamburger/arrow change? Or is all this built-in to the latest API 21?
-
ianhanniballake over 9 years@mraviator - the nav drawer and toggle are only part of the support library
-
mraviator over 9 years@ianhanniballake So I need to use v7 ActionBarDrawerToggle and define my Toolbar in XML in order to include it in the ActionBarDrawerToggle(), as indicate in the answer below by Yong?
-
ianhanniballake over 9 years@mraviator - yep: change XML, then create and attach the v7
ActionBarDrawerToggle
. The canonical answer from the maker of AppCompat has a full example how your XML should be structured. -
Nitin Misra over 9 years@BamsBamx add
android:layout_marginTop="?attr/actionBarSize"
to root layout of drawer content -
Ankit Bansal over 9 yearsWill this animation persist if we use old ActionBarCompat and not the new Toolbar ?
-
aheuermann over 9 yearsI ran into issues getting the hamburger icon to show up. calling
mDrawerToggle.syncState();
fixed it. -
ChallengeAccepted over 9 yearsTo use Toolbar as an action bar (cosmetic wise), you want to hide the actionbar by doing getSupportActionBar().hide();
-
Ramesh_D over 9 yearsfor me getSupportActionBar() returns null.. what could be the reason ?
-
wzieba over 9 yearshow you use
getSupportActionBar()
when you just extendActivity
? -
Nitin Misra over 9 yearssimply you can't, you must extend from
ActionBarActivity
-
pez over 9 yearsAndroid Studio says
Cannot resolve method setSupportActionBar(android.widget.Toolbar)
. I've also tried withandroid.support.v7.toolbar
. Does anyone know why this happens? -
gbhall over 9 years@pez Found a solution?
-
Yong over 9 years@pez Your Activity should extend ActionBarActivity. ActionBarActivity has that method.
-
SweetWisher ツ over 9 yearsThis works perfect but I don't want to use Title so how can I handle this ? Because if i use Theme.AppCompat.Light.NoActionBar, it will definitely give me NULL at getSupportActionBar
-
SweetWisher ツ over 9 yearsI used the same code but i want to hide actionBar i.e. want to use
Theme.AppCompat.Light.NoActionBar
. If I apply this theme, getSupportActionBar() will give me error ? how can I achieve this ? @Yong -
SweetWisher ツ over 9 yearsI used
setSupportActionBar(mToolbar);
and also defined<item name="spinBars">true</item>
but animation not working -
Peter Zhao about 9 yearsShould use ActionBarDrawerToggle(Activity, DrawerLayout, int, int) if you are setting the Toolbar as the ActionBar of your activity.
-
Thirumalvalavan almost 9 yearsI used above code. I got Exception: This Activity already has an action bar supplied by the window decor in setsupportactionbar(toolbar) line. I used getSupportActionBar().hide(); Before setContentView(R.layout.activity_main); Now it is working.
-
Thirumalvalavan almost 9 yearssetSupportActionBar(toolbar); also commented.
-
WISHY almost 9 yearshi cannot find drawerArrowStyle in styles. It doest not exist . Using appcompat-v7:22.2.0
-
harsimranb almost 8 yearsFYI: setDrawerListener is deprecated. You should instead use
addDrawerListener()
.