15

I am using a Nexus 7 with the Android 5.0 preview build.

On this page http://developer.android.com/tools/support-library/index.html

I see

Changes for v7 appcompat library: Updated ActionBarDrawerToggle, which contains the menu-to-arrow animation

Is this what the Google Play app uses? Am I reading too much into this statement? What do I need to change to get this behavior - I can't find it in the API documentation.

hichris123
  • 10,145
  • 15
  • 56
  • 70
Jason Hocker
  • 6,879
  • 9
  • 46
  • 79
  • Yes it is, and you just need to use ActionBarDrawerToggle from appcompat-v7 (not the old one from support-v4) with the default up indicator. – alanv Oct 17 '14 at 18:13

5 Answers5

23

I've posted a sample app here that uses the new Toolbar class and ActionBarToggle to provide an ActionBar with the Play Store style animating icon:

https://github.com/03lafaye/LollipopDrawerToggle

The no-v7-support branch uses the ActionBarToggle with a framework Activity and Toolbar. The master branch uses the v7 Toolbar and an ActionBarActivity.

The setup for not using an ActionBarActivity looks like this:

package com.plafayette.lollipop;

import android.app.Activity;
import android.support.v4.widget.DrawerLayout;
import android.os.Bundle;
import android.support.v7.app.ActionBarDrawerToggle;
import android.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;

public class ToolbarActivity extends Activity {
    private ActionBarDrawerToggle toggle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_toolbar);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setActionBar(toolbar);

        DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        toggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open, R.string.close);
        toggle.setDrawerIndicatorEnabled(true);
        drawerLayout.setDrawerListener(toggle);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        toggle.syncState();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.toolbar, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (toggle.onOptionsItemSelected(item))
            return true;

        int id = item.getItemId();
        return id == R.id.action_settings || super.onOptionsItemSelected(item);
    }
}

Note that you have to disable the window actionbar and title bar in your theme like so:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="android:Theme.Material.Light">
        <item name="android:windowActionBar">false</item>
        <item name="android:windowNoTitle">true</item>
    </style>
</resources>

I imagine the sample code for the latest v7 appcompat library will be released soon enough making this post obsolete.

Chris Renke from Square published an alternate backport of the up icon animation. The code is on GitHub here: https://github.com/ChrisRenke/DrawerArrowDrawable and he wrote a blog about it at http://chrisrenke.com/drawerarrowdrawable.

Pierre-Antoine LaFayette
  • 24,222
  • 8
  • 54
  • 58
  • How do you get the drawer icon to NOT change into back arrow when a drawer item is selected? I want the icon to remain the same in all drawer fragments. – Sndn Feb 11 '15 at 11:48
12

It is very easy.

Your layout with DrawerLayout looks the same as always. You use android.support.v4.widget.DrawerLayout and create drawers and content area:

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<RelativeLayout
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff0"
    android:orientation="vertical" >
</RelativeLayout>

<ListView
    android:id="@+id/leftDrawer"
    android:layout_width="290dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="#f0f"
    android:choiceMode="singleChoice"
    android:clickable="true"
    android:divider="@null"
    android:dividerHeight="0dp"
    android:scrollbars="none" />

Main changes are in your java code. In your Activity, where you use drawer layout, you have to extend it for ActionBarActivity from v7. Then you create variables for DrawerLayout and ActionBarDrawerToggle. Your imports should look like this:

import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.ActionBarActivity;

and then just connect everything. Remember that new drawer layout does not have icon! You just dont pass it where you normally should be. Code for my activity:

import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.ActionBarActivity;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity {

    DrawerLayout drawerLayout;
    ActionBarDrawerToggle drawerToggle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.app_name, R.string.app_name) {};

        drawerLayout.setDrawerListener(drawerToggle);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (drawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

}

And it should work.

  • Is using the compatibility ActionBarActivity necessary? – Jason Hocker Oct 17 '14 at 22:01
  • If you are using `Toolbar` widget from support library and `NoActionBar` theme you should be using `ActionBarActivity` too, to use `setActionBar(Toolbar)` method. In both cases you should be using if you want to support older versions. – Nikola Despotoski Oct 18 '14 at 01:09
10

Check out here

enter image description here

MainActivity.java:

package com.poliveira.apps.materialtests;

import android.os.Bundle;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.widget.Toast;


public class MainActivity extends ActionBarActivity implements NavigationDrawerCallbacks {

    private Toolbar mToolbar;
    private NavigationDrawerFragment mNavigationDrawerFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar);
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowHomeEnabled(true);

        mNavigationDrawerFragment = (NavigationDrawerFragment) getFragmentManager().findFragmentById(R.id.fragment_drawer);
        mNavigationDrawerFragment.setup(R.id.fragment_drawer, (DrawerLayout) findViewById(R.id.drawer), mToolbar);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public void onNavigationDrawerItemSelected(int position) {
        Toast.makeText(this, "Menu item selected -> " + position, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onBackPressed() {
        if (mNavigationDrawerFragment.isDrawerOpen())
            mNavigationDrawerFragment.closeDrawer();
        else
            super.onBackPressed();
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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">

    <include
        android:id="@+id/toolbar_actionbar"
        layout="@layout/toolbar_default"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawer"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/toolbar_actionbar">

        <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:clickable="true"
            android:layout_height="match_parent"/>

        <!-- android:layout_marginTop="?android:attr/actionBarSize"-->
        <fragment
            android:id="@+id/fragment_drawer"
            android:name="com.poliveira.apps.materialtests.NavigationDrawerFragment"
            android:layout_width="@dimen/navigation_drawer_width"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            app:layout="@layout/fragment_navigation_drawer"/>
    </android.support.v4.widget.DrawerLayout>
</RelativeLayout>
Stephen
  • 9,899
  • 16
  • 90
  • 137
  • 2
    This in my opinion is the best answer for the question, direct to the point with a clean project link – Maya Jan 19 '15 at 18:20
  • Do you need to use the same layout and same class implementation if you need to move from this activity to another? For example do I need to extend the new activity to be based on the actionbar if i wanted to display the action bar in the new activity? – Maya Jan 20 '15 at 20:20
  • @Maya I didn't get you.You have to implement in right way to get the expected result – Stephen Jan 21 '15 at 04:40
  • Sorry I didn't explain myself well :) I have implemented your ActionBar code above as it is and it worked perfectly, exactly what I wanted, then I tried to use it with multiple activities without recreating the ActionBar in every activity layout Im using, so I created a BaseActivity which contains the implementation of the action bar and I extended all my activities to use the BaseActivity, I however have problems initialising the fragments every time I jump from an activity to another. Not sure if there is an example out there using your ActionBar with multiple activities. – Maya Jan 21 '15 at 07:39
  • I don't know if I can post the code here or PM you some where – Maya Jan 21 '15 at 07:51
9

You seem to have a working drawer as I read it, if not, the Documentation on "Creating a Navigation Drawer" is pretty good.

Updated ActionBarDrawerToggle, which contains the menu-to-arrow animation

enter image description here

The above quote refers to Create a new ActionBarDrawerToggle with arrow and hamburger menu commit. As a related one: setDrawerIndicatorEnabled was added in Add ability to disable drawer indicator in new ArrowDrawer.

So make sure setDrawerIndicatorEnabled is not called with false and use

import android.support.v7.app.ActionBarDrawerToggle;

instead of

import android.support.v4.app.ActionBarDrawerToggle;

which should be pretty obvious from deprecation warnings anyway:

@deprecated Please use ActionBarDrawerToggle in support-v7-appcompat.

Probably also need

// <item name="displayOptions">showHome|homeAsUp</item>
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
8

First, make sure you update to latest SDK. Create new Project in Android Studio, then add appcompat-v7.21.0.+ and appcompat-v4.21.0.+ libraries in your buid.gradle as gradle dependency.

compile 'com.android.support:appcompat-v7:21.0.2'
compile 'com.android.support:support-v4:21.0.2'

Add primaryColor and primarycolorDark in your color.xml file.

<resources>
<color name="primaryColor">#2196F3</color>
<color name="primaryColorDark">#0D47A1</color>
</resources>

Add drawer open/close string value in your strings.xml file.

<resources>
<string name="app_name">Lollipop Drawer</string>
<string name="action_settings">Settings</string>
<string name="drawer_open">open</string>
<string name="drawer_close">close</string>
</resources>

Your activity_my.xml layout file looks like this:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">

<include layout="@layout/toolbar" />


<android.support.v4.widget.DrawerLayout
    android:layout_width="match_parent"
    android:id="@+id/drawerLayout"
    android:layout_height="match_parent">

    <!-- activity view -->
    <RelativeLayout
        android:layout_width="match_parent"
        android:background="#fff"
        android:layout_height="match_parent">

        <TextView
            android:layout_centerInParent="true"
            android:layout_width="wrap_content"
            android:textColor="#000"
            android:text="Activity Content"
            android:layout_height="wrap_content" />
    </RelativeLayout>

    <!-- navigation drawer -->
    <RelativeLayout
        android:layout_gravity="left|start"
        android:layout_width="match_parent"
        android:background="#fff"
        android:layout_height="match_parent">

        <ListView
            android:id="@+id/left_drawer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="#eee"
            android:background="#fff"
            android:dividerHeight="1dp" />
    </RelativeLayout>

</android.support.v4.widget.DrawerLayout>

</LinearLayout>

Your toolbar.xml layout file looks like this:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content">

</android.support.v7.widget.Toolbar>

Your MyActivity.java looks like this: Here your activity must extends ActionBarActivity and set your toolbar as support actionbar.

import android.content.res.Configuration;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MyActivity extends ActionBarActivity {

private Toolbar toolbar;
private DrawerLayout drawerLayout;
private ActionBarDrawerToggle drawerToggle;
private ListView leftDrawerList;
private ArrayAdapter<String> navigationDrawerAdapter;
private String[] leftSliderData = {"Home", "Android", "Sitemap", "About", "Contact Me"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    nitView();
    if (toolbar != null) {
        toolbar.setTitle("Navigation Drawer");
        setSupportActionBar(toolbar);
    }
    initDrawer();
}

private void nitView() {
    leftDrawerList = (ListView) findViewById(R.id.left_drawer);
    toolbar = (Toolbar) findViewById(R.id.toolbar);
    drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
    navigationDrawerAdapter=new ArrayAdapter<String>( MyActivity.this, android.R.layout.simple_list_item_1, leftSliderData);
    leftDrawerList.setAdapter(navigationDrawerAdapter);
}

private void initDrawer() {

    drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {

        @Override
        public void onDrawerClosed(View drawerView) {
            super.onDrawerClosed(drawerView);

        }

        @Override
        public void onDrawerOpened(View drawerView) {
            super.onDrawerOpened(drawerView);

        }
    };
    drawerLayout.setDrawerListener(drawerToggle);
}

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    drawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    drawerToggle.onConfigurationChanged(newConfig);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.my, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    if (drawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}
}

Create style.xml file in values-21 folder for android lollipop

<?xml version="1.0" encoding="utf-8"?>
<resources>

<style name="myAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/primaryColor</item>
    <item name="colorPrimaryDark">@color/primaryColorDark</item>
    <item name="android:statusBarColor">@color/primaryColorDark</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/black</item>
</style>

</resources>

Create your style.xml file in values folder for older versions then android lollipop

<resources>

<style name="myAppTheme" parent="Theme.AppCompat.Light">
    <item name="colorPrimary">@color/primaryColor</item>
    <item name="colorPrimaryDark">@color/primaryColorDark</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/black</item>
</style>

</resources>

Your AndroidManifest.xml is looks like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="nkdroid.com.lollipopdrawer" >

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/myAppTheme" >
    <activity
        android:name=".MyActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>

For reference only: you can download complete source code from here : click here

nirav kalola
  • 1,220
  • 13
  • 17