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