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