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 17 package androidx.appcompat.app; 18 19 import android.content.res.Configuration; 20 import android.content.res.Resources; 21 import android.content.res.TypedArray; 22 import android.os.Bundle; 23 import android.view.MenuItem; 24 import android.view.View; 25 import android.view.ViewTreeObserver; 26 import android.widget.AdapterView; 27 import android.widget.ArrayAdapter; 28 import android.widget.ListView; 29 import android.widget.TextView; 30 31 import androidx.appcompat.test.R; 32 import androidx.appcompat.testutils.BaseTestActivity; 33 import androidx.appcompat.testutils.Shakespeare; 34 import androidx.appcompat.widget.Toolbar; 35 import androidx.core.view.GravityCompat; 36 import androidx.drawerlayout.widget.DrawerLayout; 37 38 /** 39 * Test activity for testing various APIs and interactions for DrawerLayout. It follows 40 * a common usage of the DrawerLayout widget combined with Toolbar in the Android support library 41 * that respect the 42 * <a href="https://www.google.com/design/spec/patterns/navigation-drawer.html">Material design 43 * guidelines</a> for the drawer component. 44 */ 45 public class DrawerLayoutActivity extends BaseTestActivity { 46 private DrawerLayout mDrawerLayout; 47 private ListView mDrawer; 48 private TextView mContent; 49 50 private ActionBarDrawerToggle mDrawerToggle; 51 private Toolbar mToolbar; 52 53 @Override 54 protected int getContentViewLayoutResId() { 55 return R.layout.drawer_layout; 56 } 57 58 @Override 59 protected void onContentViewSet() { 60 super.onContentViewSet(); 61 62 mDrawerLayout = findViewById(R.id.drawer_layout); 63 mDrawer = findViewById(R.id.start_drawer); 64 mContent = findViewById(R.id.content_text); 65 66 mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); 67 68 // The drawer title must be set in order to announce state changes when 69 // accessibility is turned on. This is typically a simple description, 70 // e.g. "Navigation". 71 mDrawerLayout.setDrawerTitle(GravityCompat.START, getString(R.string.drawer_title)); 72 73 mDrawer.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, 74 Shakespeare.TITLES)); 75 mDrawer.setOnItemClickListener(new DrawerItemClickListener()); 76 77 // Find the toolbar in our layout and set it as the support action bar on the activity. 78 // This is required to have the drawer slide "over" the toolbar. 79 mToolbar = findViewById(R.id.toolbar); 80 mToolbar.setTitle(R.string.drawer_title); 81 setSupportActionBar(mToolbar); 82 83 getSupportActionBar().setDisplayHomeAsUpEnabled(true); 84 getSupportActionBar().setDisplayShowHomeEnabled(false); 85 86 // ActionBarDrawerToggle provides convenient helpers for tying together the 87 // prescribed interactions between a top-level sliding drawer and the action bar. 88 // Note that, as the Javadocs of ActionBarDrawerToggle constructors say, we are 89 // *not* using a constructor that gets a Toolbar since we're setting our toolbar 90 // dynamically at runtime. Furthermore, as the drawer is sliding over the toolbar, 91 // we are suppressing the morphing animation from hamburger to back arrow by 92 // calling super.onDrawerSlide with slideOffset=0.0f. In case your app only has 93 // top-level pages and doesn't need back arrow visuals at all, you can set up 94 // your activity theme to have attribute named "drawerArrowStyle" that points 95 // to an extension of Widget.AppCompat.DrawerArrowToggle that has its "spinBars" 96 // attribute set to false. 97 mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 98 R.string.drawer_open, R.string.drawer_close) { 99 @Override 100 public void onDrawerOpened(View drawerView) { 101 super.onDrawerOpened(drawerView); 102 super.onDrawerSlide(drawerView, 0.0f); 103 } 104 105 @Override 106 public void onDrawerSlide(View drawerView, float slideOffset) { 107 super.onDrawerSlide(drawerView, 0.0f); 108 } 109 }; 110 111 mDrawerLayout.addDrawerListener(mDrawerToggle); 112 113 // Configure the background color fill of the system status bar (on supported platform 114 // versions) and the toolbar itself. We're using the same color, and android:statusBar 115 // from the theme makes the status bar slightly darker. 116 final int metalBlueColor = getResources().getColor(R.color.drawer_sample_metal_blue); 117 mDrawerLayout.setStatusBarBackgroundColor(metalBlueColor); 118 mToolbar.setBackgroundColor(metalBlueColor); 119 120 // Register a pre-draw listener to get the initial width of the DrawerLayout so 121 // that we can determine the width of the drawer based on the Material spec at 122 // https://www.google.com/design/spec/patterns/navigation-drawer.html#navigation-drawer-specs 123 mDrawerLayout.getViewTreeObserver().addOnPreDrawListener( 124 new ViewTreeObserver.OnPreDrawListener() { 125 @Override 126 public boolean onPreDraw() { 127 // What is the width of the entire DrawerLayout? 128 final int drawerLayoutWidth = mDrawerLayout.getWidth(); 129 130 // What is the action bar size? 131 final Resources.Theme theme = mDrawerLayout.getContext().getTheme(); 132 final TypedArray a = theme.obtainStyledAttributes( 133 new int[] { androidx.appcompat.R.attr.actionBarSize }); 134 final int actionBarSize = a.getDimensionPixelSize(0, 0); 135 if (a != null) { 136 a.recycle(); 137 } 138 139 // Compute the width of the drawer and set it on the layout params. 140 final int idealDrawerWidth = 5 * actionBarSize; 141 final int maxDrawerWidth = Math.max(0, drawerLayoutWidth - actionBarSize); 142 final int drawerWidth = Math.min(idealDrawerWidth, maxDrawerWidth); 143 144 final DrawerLayout.LayoutParams drawerLp = 145 (DrawerLayout.LayoutParams) mDrawer.getLayoutParams(); 146 drawerLp.width = drawerWidth; 147 mDrawer.setLayoutParams(drawerLp); 148 149 // Remove ourselves as the pre-draw listener since this is a one-time 150 // configuration. 151 mDrawerLayout.getViewTreeObserver().removeOnPreDrawListener(this); 152 return true; 153 } 154 }); 155 } 156 157 @Override 158 protected void onPostCreate(Bundle savedInstanceState) { 159 super.onPostCreate(savedInstanceState); 160 161 // Sync the toggle state after onRestoreInstanceState has occurred. 162 mDrawerToggle.syncState(); 163 } 164 165 @Override 166 public boolean onOptionsItemSelected(MenuItem item) { 167 /* 168 * The action bar home/up action should open or close the drawer. 169 * The drawer toggle will take care of this. 170 */ 171 if (mDrawerToggle.onOptionsItemSelected(item)) { 172 return true; 173 } 174 return super.onOptionsItemSelected(item); 175 } 176 177 @Override 178 public void onBackPressed() { 179 // Is the drawer open? 180 if (mDrawerLayout.isDrawerOpen(mDrawer)) { 181 // Close the drawer and return. 182 mDrawerLayout.closeDrawer(mDrawer); 183 return; 184 } 185 186 super.onBackPressed(); 187 } 188 189 @Override 190 public void onConfigurationChanged(Configuration newConfig) { 191 super.onConfigurationChanged(newConfig); 192 mDrawerToggle.onConfigurationChanged(newConfig); 193 } 194 195 /** 196 * This list item click listener implements very simple view switching by changing 197 * the primary content text. The drawer is closed when a selection is made. 198 */ 199 private class DrawerItemClickListener implements ListView.OnItemClickListener { 200 @Override 201 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 202 mContent.setText(Shakespeare.DIALOGUE[position]); 203 mToolbar.setTitle(Shakespeare.TITLES[position]); 204 mDrawerLayout.closeDrawer(mDrawer); 205 } 206 } 207 } 208