1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.supportv7.widget;
18
19import android.content.res.Configuration;
20import android.content.res.Resources;
21import android.content.res.TypedArray;
22import android.os.Bundle;
23import android.support.v4.content.ContextCompat;
24import android.support.v4.view.GravityCompat;
25import android.support.v4.widget.DrawerLayout;
26import android.support.v7.app.ActionBarDrawerToggle;
27import android.support.v7.app.AppCompatActivity;
28import android.support.v7.widget.Toolbar;
29import android.view.MenuItem;
30import android.view.View;
31import android.view.ViewTreeObserver;
32import android.widget.AdapterView;
33import android.widget.ArrayAdapter;
34import android.widget.FrameLayout;
35import android.widget.ListView;
36import android.widget.TextView;
37import com.example.android.supportv7.R;
38import com.example.android.supportv7.Shakespeare;
39
40/**
41 * This example illustrates a common usage of the DrawerLayout widget combined with Toolbar
42 * in the Android support library that respect the
43 * <a href="https://www.google.com/design/spec/patterns/navigation-drawer.html">Material design
44 * guidelines</a> for the drawer component.
45 *
46 *
47 * <p>A DrawerLayout should be positioned at the top of your view hierarchy, placing it
48 * below the action bar but above your content views. The primary content should match_parent
49 * in both dimensions. Each drawer should define a reasonable width and match_parent for height.
50 * Drawer views should be positioned after the content view in your layout to preserve proper
51 * ordering.</p>
52 *
53 * <p>When a navigation (left) drawer is present, the host activity should detect presses of
54 * the action bar's Up affordance as a signal to open and close the navigation drawer.
55 * Items within the drawer should fall into one of two categories.</p>
56 *
57 * <ul>
58 *     <li><strong>View switches</strong>. A view switch follows the same basic policies as
59 *     list or tab navigation in that a view switch does not create navigation history.
60 *     This pattern should only be used at the root activity of a task, leaving some form
61 *     of Up navigation active for activities further down the navigation hierarchy.</li>
62 *     <li><strong>Selective Up</strong>. The drawer allows the user to choose an alternate
63 *     parent for Up navigation. This allows a user to jump across an app's navigation
64 *     hierarchy at will. The application should treat this as it treats Up navigation from
65 *     a different task, replacing the current task stack using TaskStackBuilder or similar.
66 *     This is the only form of navigation drawer that should be used outside of the root
67 *     activity of a task.</li>
68 * </ul>
69 *
70 * <p>Right side drawers should be used for actions, not navigation. This follows the pattern
71 * established by the Action Bar that navigation should be to the left and actions to the right.
72 * An action should be an operation performed on the current contents of the window,
73 * for example enabling or disabling a data overlay on top of the current content.</p>
74 *
75 * <p>When the drawer is open, it is above the application toolbar. On Lollipop versions of the
76 * platform and above the drawer spans the full height of the screen, including behind the system
77 * status bar.</p>
78 */
79public class DrawerLayoutActivity extends AppCompatActivity {
80    private DrawerLayout mDrawerLayout;
81    private ListView mStartDrawer;
82    private FrameLayout mEndDrawer;
83    private TextView mContent;
84
85    private ActionBarDrawerToggle mDrawerToggle;
86    private Toolbar mToolbar;
87
88    @Override
89    protected void onCreate(Bundle savedInstanceState) {
90        super.onCreate(savedInstanceState);
91
92        setContentView(R.layout.drawer_layout);
93
94        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
95        mStartDrawer = (ListView) findViewById(R.id.start_drawer);
96        mEndDrawer = (FrameLayout) findViewById(R.id.end_drawer);
97        mContent = (TextView) findViewById(R.id.content_text);
98
99        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
100        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow_end, GravityCompat.END);
101
102        // The drawer title must be set in order to announce state changes when
103        // accessibility is turned on. This is typically a simple description,
104        // e.g. "Navigation".
105        mDrawerLayout.setDrawerTitle(GravityCompat.START, getString(R.string.drawer_title));
106
107        mStartDrawer.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
108                Shakespeare.TITLES));
109        mStartDrawer.setOnItemClickListener(new DrawerItemClickListener());
110
111        // Find the toolbar in our layout and set it as the support action bar on the activity.
112        // This is required to have the drawer slide "over" the toolbar.
113        mToolbar = (Toolbar) findViewById(R.id.toolbar);
114        mToolbar.setTitle(R.string.drawer_title);
115        setSupportActionBar(mToolbar);
116
117        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
118        getSupportActionBar().setDisplayShowHomeEnabled(false);
119
120        // ActionBarDrawerToggle provides convenient helpers for tying together the
121        // prescribed interactions between a top-level sliding drawer and the action bar.
122        // Note that, as the Javadocs of ActionBarDrawerToggle constructors say, we are
123        // *not* using a constructor that gets a Toolbar since we're setting our toolbar
124        // dynamically at runtime. Furthermore, as the drawer is sliding over the toolbar,
125        // we are suppressing the morphing animation from hamburger to back arrow by
126        // calling super.onDrawerSlide with slideOffset=0.0f. In case your app only has
127        // top-level pages and doesn't need back arrow visuals at all, you can set up
128        // your activity theme to have attribute named "drawerArrowStyle" that points
129        // to an extension of Widget.AppCompat.DrawerArrowToggle that has its "spinBars"
130        // attribute set to false.
131        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
132                R.string.drawer_open, R.string.drawer_close) {
133            @Override
134            public void onDrawerOpened(View drawerView) {
135                super.onDrawerOpened(drawerView);
136                super.onDrawerSlide(drawerView, 0.0f);
137            }
138
139            @Override
140            public void onDrawerSlide(View drawerView, float slideOffset) {
141                super.onDrawerSlide(drawerView, 0.0f);
142            }
143        };
144
145        mDrawerLayout.addDrawerListener(mDrawerToggle);
146
147        // Configure the background color fill of the system status bar (on supported platform
148        // versions) and the toolbar itself. We're using the same color, and android:statusBar
149        // from the theme makes the status bar slightly darker.
150        final int metalBlueColor = ContextCompat.getColor(this, R.color.drawer_sample_metal_blue);
151        mDrawerLayout.setStatusBarBackgroundColor(metalBlueColor);
152        mToolbar.setBackgroundColor(metalBlueColor);
153
154        // Register a pre-draw listener to get the initial width of the DrawerLayout so
155        // that we can determine the width of the drawer based on the Material spec at
156        // https://www.google.com/design/spec/patterns/navigation-drawer.html#navigation-drawer-specs
157        mDrawerLayout.getViewTreeObserver().addOnPreDrawListener(
158                new ViewTreeObserver.OnPreDrawListener() {
159                    @Override
160                    public boolean onPreDraw() {
161                        // What is the width of the entire DrawerLayout?
162                        final int drawerLayoutWidth = mDrawerLayout.getWidth();
163
164                        // What is the action bar size?
165                        final Resources.Theme theme = mDrawerLayout.getContext().getTheme();
166                        final TypedArray a = theme.obtainStyledAttributes(
167                                new int[] { android.support.v7.appcompat.R.attr.actionBarSize });
168                        final int actionBarSize = a.getDimensionPixelSize(0, 0);
169                        if (a != null) {
170                            a.recycle();
171                        }
172
173                        // Compute the width of the drawer and set it on the layout params.
174                        final int idealDrawerWidth = 5 * actionBarSize;
175                        final int maxDrawerWidth = Math.max(0, drawerLayoutWidth - actionBarSize);
176                        final int drawerWidth = Math.min(idealDrawerWidth, maxDrawerWidth);
177
178                        final DrawerLayout.LayoutParams startDrawerLp =
179                                (DrawerLayout.LayoutParams) mStartDrawer.getLayoutParams();
180                        startDrawerLp.width = drawerWidth;
181                        mStartDrawer.setLayoutParams(startDrawerLp);
182
183                        final DrawerLayout.LayoutParams endDrawerLp =
184                                (DrawerLayout.LayoutParams) mEndDrawer.getLayoutParams();
185                        endDrawerLp.width = drawerWidth;
186                        mEndDrawer.setLayoutParams(endDrawerLp);
187
188                        // Remove ourselves as the pre-draw listener since this is a one-time
189                        // configuration.
190                        mDrawerLayout.getViewTreeObserver().removeOnPreDrawListener(this);
191                        return true;
192                    }
193        });
194    }
195
196    @Override
197    protected void onPostCreate(Bundle savedInstanceState) {
198        super.onPostCreate(savedInstanceState);
199
200        // Sync the toggle state after onRestoreInstanceState has occurred.
201        mDrawerToggle.syncState();
202    }
203
204    @Override
205    public boolean onOptionsItemSelected(MenuItem item) {
206        /*
207         * The action bar home/up action should open or close the drawer.
208         * The drawer toggle will take care of this.
209         */
210        if (mDrawerToggle.onOptionsItemSelected(item)) {
211            return true;
212        }
213        return super.onOptionsItemSelected(item);
214    }
215
216    @Override
217    public void onBackPressed() {
218        boolean hadOpenDrawer = false;
219        // Is the start drawer open?
220        if (mDrawerLayout.isDrawerOpen(mStartDrawer)) {
221            // Close it
222            mDrawerLayout.closeDrawer(mStartDrawer);
223            hadOpenDrawer = true;
224        }
225        // Is the end drawer open?
226        if (mDrawerLayout.isDrawerOpen(mEndDrawer)) {
227            // Close it
228            mDrawerLayout.closeDrawer(mEndDrawer);
229            hadOpenDrawer = true;
230        }
231
232        if (hadOpenDrawer) {
233            // If we had one or both drawers open, now that we've closed it / them, return.
234            return;
235        }
236
237        super.onBackPressed();
238    }
239
240    @Override
241    public void onConfigurationChanged(Configuration newConfig) {
242        super.onConfigurationChanged(newConfig);
243        mDrawerToggle.onConfigurationChanged(newConfig);
244    }
245
246    /**
247     * This list item click listener implements very simple view switching by changing
248     * the primary content text. The drawer is closed when a selection is made.
249     */
250    private class DrawerItemClickListener implements ListView.OnItemClickListener {
251        @Override
252        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
253            mContent.setText(Shakespeare.DIALOGUE[position]);
254            mToolbar.setTitle(Shakespeare.TITLES[position]);
255            mDrawerLayout.closeDrawer(mStartDrawer);
256        }
257    }
258}
259