Drawer 详解 ·Material Design Part 3

ccheima 7年前
   <p style="text-align:center"><img src="https://simg.open-open.com/show/ac0bc119cf8203e4d4a9250f94f8997e.png"></p>    <p>这是一个系列文章,在这个系列里,我会按打造一个Material Design App的路线介绍所有应当掌握和值得掌握的系统组件。</p>    <p>你会在这些文章里了解到这些组件的使用和内部实现原理,以及它们背后所反映的Material Design的设计思想,希望你会喜欢。</p>    <h2><strong>前言</strong></h2>    <p>上一篇我介绍了有关Toolbar的知识点,在Toolbar的最左侧,可以有一个导航按钮的存在,它可以是一个向上键,可以是个菜单开关或者其他任何的样式。</p>    <p>通常在App首页,我们更多的见到它以一个菜单样式的图案呈现,点击该按钮,会从App的侧边弹出一个新页面,我们称之为“抽屉”。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/20975408b959afa4db02311e74b27fe9.jpg"></p>    <p>在这篇文章里,我会 <strong>介绍抽屉在APP中的作用,以及如何通过</strong> <strong>Drawerlayout&NavigationView来实现抽屉,顺便说下我采用的抽屉菜单延伸至状态栏的方法。</strong></p>    <h2><strong>目录</strong></h2>    <ol>     <li>Navigation Drawer简介</li>     <li>DrawerLayout详解</li>     <li>代码示例(一)</li>     <li>NavigationView介绍</li>     <li><strong>将DrawerLayout延伸至状态栏</strong></li>     <li>代码示例(二)</li>     <li><strong><u>几句额外的</u> </strong></li>    </ol>    <h2><strong>Navigation Drawer简介</strong></h2>    <p>就像我一直强调的, <strong>Material Design的世界就是一个真实世界的缩影。一个优秀的Material Design组件,要么反映了真实世界里事物的功能和特性,要么反映了真实世界里的行为逻辑。</strong></p>    <p>举个例子,大家都使用过抽屉,我们通常会将 <strong>比较常用但又不需要每时每刻都使用</strong> 的东西放在抽屉里。在需要的时候,我们能准确且稳定地在指定地点找到;不需要的时候可以很好地隐藏和存放,不占用更多的可见空间。在我们的app里,也一定有数个这样的操作入口:它们 <strong>比较常用</strong> , <strong>但又不需要每时每刻都看见</strong> 。这时,我们自然就需要一个地方来存放它们,这就是我今天想要介绍的“抽屉导航栏”。</p>    <p>为了实现这样的效果,Android官方提供了 <strong>DrawerLayout</strong> ,通过它我们便可以轻松创造出一个“抽屉”,下面就让我们一起来详细了解一下它。</p>    <h2><strong>DrawerLayout详解</strong></h2>    <p>首先是使用,DrawerLayout的使用可以非常简单,仅需要如下的XML代码便能实现两侧都可以拉出抽屉的效果:</p>    <pre>  <code class="language-java"><android.support.v4.widget.DrawerLayout      xmlns:android="http://schemas.android.com/apk/res/android"      android:id="@+id/drawer_layout"      android:layout_width="match_parent"      android:layout_height="match_parent">      <!-- 主内容 -->      <LinearLayout          android:id="@+id/content_frame"          android:layout_width="match_parent"          android:layout_height="match_parent" />        <!-- 抽屉导航栏1 -->      <RelativeLayout android:id="@+id/left_drawer"          android:layout_width="240dp"          android:layout_height="100dp"          android:layout_gravity="start"/>        <!-- 抽屉导航栏2 -->      <RelativeLayout android:id="@+id/right_drawer"          android:layout_width="240dp"          android:layout_height="match_parent"          android:layout_gravity="end"/>    </android.support.v4.widget.DrawerLayout></code></pre>    <p><strong>不过我们还是需要记住几点:</strong></p>    <ol>     <li>在Drawerlayout中, <strong>主内容视图必须是第一个子视图</strong> 。因为XML里是按层叠顺序进行排序的,后面的内容会盖过前面的内容,而抽屉视图应位于页面顶部。</li>     <li><strong>抽屉视图必须通过"android:layout_gravity"指定其重心位置</strong> ,建议使用"start"&"end"来支持RTL(从右到左)语言。</li>     <li>主内容视图的长宽都应“match_parent”,因为当抽屉收起时它代表整个UI界面。</li>     <li>抽屉部分的高度应设为match_parent,而宽度不应超过320dp,以便让用户仍可以看到部分主内容。</li>    </ol>    <p>当然,仅仅只是这样对我们的日常开发显然是不够的,我们需要对Drawerlayout有更多的细节处的掌控,对此Drawerlayout提供了简便的API,下面我们就来了解一下。</p>    <p><strong><u>常用方法详解</u> </strong></p>    <ul>     <li><strong>openDrawer()方法用于打开“抽屉”,有四种参数形式:</strong>      <ul>       <li><strong>(View drawerView):</strong> 打开传入的抽屉视图。</li>       <li><strong>(int gravity):</strong> 打开传入的相应gravity上的抽屉视图。</li>       <li><strong>(View drawerView, boolean animate):</strong> 打开传入的抽屉视图,第二个参数用于控制是否开启视图滑入动画。</li>       <li><strong>(int gravity, boolean animate):</strong> 打开传入的相应gravity上的抽屉视图,第二个参数用于控制是否开启视图滑入动画。</li>      </ul> </li>     <li><strong>closeDrawer()方法用于关闭“抽屉”,有四种参数形式:</strong>      <ul>       <li><strong>closeDrawer(View drawerView):</strong> 关闭传入的抽屉视图。</li>       <li><strong>closeDrawer(int gravity):</strong> 关闭传入的相应gravity上的抽屉视图。</li>       <li><strong>closeDrawer(View drawView, boolean animate):</strong> 关闭传入的抽屉视图,第二个参数用于控制是否开启视图退出动画。</li>       <li><strong>closeDrawer(int gravity, boolean animate):</strong> 关闭传入的相应gravity上的抽屉视图,第二个参数用于控制是否开启视图退出动画。</li>      </ul> </li>    </ul>    <ul>     <li><strong>closeDrawers():</strong> 关闭所有的抽屉视图。</li>    </ul>    <ul>     <li><strong>setDrawerTitle(int edgeGravity, CharSequence title):</strong> 依据传入的gravity来给相应的Drawer设置title,设置title的目的是用于无障碍服务(Accessibility Service)。</li>     <li><strong>CharSequence getDrawerTitle(int edgeGravity):</strong> 依据传入的gravity来获取相应Drawer的title。</li>     <li><strong>setDrawerElevation(float elevation):</strong> 设置抽屉视图的Z轴高度,带来的视觉上的变化为 <strong>抽屉视图的阴影发生了改变</strong> 。</li>     <li><strong>float getDrawerElevation():</strong> 用于获取抽屉视图的Z轴高度,返回值为float型。</li>    </ul>    <ul>     <li><strong>boolean isDrawerOpen(View drawer / int drawerGravity):</strong> 根据传入的参数判断相应的Drawer是否处于开启状态。</li>     <li><strong>boolean isDrawerVisible(View drawer / int drawerGravity):</strong> 根据传入的参数判断相应的Drawer当前在屏幕上是否可见。</li>     <li><strong>setScrimColor(int color):</strong> 设置当抽屉打开时,未被抽屉遮住部分的颜色。</li>    </ul>    <ul>     <li><strong>setDrawerLockMode(int lockMode / int lockMode,View drawerView / int lockMode, int edgeGravity):</strong> 该方法用于设置抽屉的锁定模式,只传入锁定模式而不指定是哪个抽屉则会将两侧的抽屉都设置一遍。<br> <strong>锁定模式有四种:</strong>      <ul>       <li>LOCK_MODE_LOCKED_CLOSED:关闭抽屉的滑动操作并将抽屉收起</li>       <li>LOCK_MODE_LOCKED_OPEN:关闭抽屉的滑动操作并将抽屉打开</li>       <li>LOCK_MODE_UNDEFINED:将锁定模式重新设置到默认状态</li>       <li>LOCK_MODE_UNLOCKED:解锁对抽屉的滑动操作锁定<br> <strong>注:</strong> 关闭抽屉的滑动操作即使 <strong> </strong> <p><u>通过滑动</u> 打开/关闭 抽屉的操作失效</p> </li>      </ul> </li>     <li><strong>addDrawerListener(DrawerLayout.DrawerListener listener):</strong> 为Drawerlayout添加监听器监听抽屉的开启关闭等事件。</li>     <li><strong>removeDrawerListener(DrawerLayout.DrawerListener listener):</strong> 移除传入的DrawerLayout的相应监听器。</li>    </ul>    <p><strong><u>Drawer监听器</u> </strong></p>    <p>上面的常用API介绍最后两条提到了为DrawerLayout添加监听器,下面就来介绍一下Drawer的监听器——DrawerListener。</p>    <p>该接口提供了四个回调方法供复写,分别是:</p>    <ul>     <li><strong>onDrawerOpened:</strong> 当抽屉处于完全打开的状态时该方法会被回调</li>     <li><strong>onDrawerClosed:</strong> 当抽屉处于完全关闭的状态时该方法会被回调</li>     <li><strong>onDrawerSlide:</strong> 当抽屉被滑动时该方法会回调</li>     <li><strong>onDrawerStateChanged:</strong> 当抽屉的状态发生变化时该方法会被回调</li>    </ul>    <p>使用DrawerListener需要将以上四个方法都实现,但如果你只需要对其中的个别方法增加逻辑话,你可以使用 <strong>SimpleDrawerListener</strong> ,它继承自DrawerListener,不需要你实现全部四个方法而是只需复写你需要用到的方法。</p>    <p><strong><u>ActionBarDrawerToggle</u> </strong></p>    <p>如果你的页面包含了Toolbar(ActionBar),那么我更建议你使用ActionBarDrawerToggle。从它的名字也可以看出,这是当我们需要将ActionBar和Drawer结合使用的最佳途径。</p>    <p>首先, <strong>ActionBarDrawerToggle该类实现了DrawerListener接口</strong> ,所以其实你可以直接将它当作DrawerListener来使用,它能做到DrawerListener可以做的任何事。同时,会有一个抽屉样式的indicator位于Toolbar(ActionBar)上,根据抽屉的打开和关闭,会有一个很自然的演变动画给予用户当前抽屉开或闭的明确提示。当然,如果你不想要那个图标,也可以自己指定一个新的图案(详情见常用方法介绍)。</p>    <p>需要注意两点:</p>    <ol>     <li>该类应配合 <strong>onConfigurationChanged()</strong> 和 <strong>onOptionsItemSelected()</strong> 使用,具体原因我直接在下面代码的注释里写吧</li>     <li>如果使用了该类,应在 <strong>onPostCreate()</strong> 方法里调用 <strong>syncState()</strong> 来将指示器(indicator)的状态和Drawer同步。</li>    </ol>    <p><strong>常用方法</strong></p>    <ul>     <li><strong>boolean isDrawerIndicatorEnabled():</strong> 返回当前指示器是否可用(可见)</li>     <li><strong>setDrawerIndicatorEnabled(boolean enable):</strong> 设置指示器是否可用(可见)</li>     <li><strong>setHomeAsUpIndicator(Drawable indicator / int resId):</strong> 当 <strong>默认的指示器不可用时</strong> 为Drawer设置一个新的指示器</li>     <li><strong>setToolbarNavigationClickListener(View.OnClickListener onToolbarNavigationClickListener):</strong> 为指示器绑定点击事件监听</li>    </ul>    <h2><strong>代码示例(一)</strong></h2>    <p><strong>效果图</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f10bc8b087904a625be03a320ff58e72.png"></p>    <p><strong>效果视频</strong></p>    <p><a href="/misc/goto?guid=4959724782371276771" rel="nofollow,noindex">Drawer详解·效果视频1—在线播放—优酷网,视频高清在线观看 http://v.youku.com/v_show/id_XMTgxNDU3ODc2OA==.html </a></p>    <p>activity_layout.xml</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:id="@+id/activity_drawer_test"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:orientation="vertical">        <include layout="@layout/content_toolbar" />        <android.support.v4.widget.DrawerLayout          android:id="@+id/drawer_layout"          android:layout_width="match_parent"          android:layout_height="match_parent">            <!--主内容-->          <LinearLayout              android:layout_width="match_parent"              android:layout_height="match_parent"              android:gravity="center"              android:orientation="vertical">                <TextView                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:text="设置蒙板颜色"                  android:textColor="@color/textPrimary"                  android:textSize="30sp" />                <RadioGroup                  android:id="@+id/radio_group"                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:layout_marginBottom="30dp">                    <RadioButton                      android:id="@+id/red_rbtn"                      android:layout_width="wrap_content"                      android:layout_height="wrap_content"                      android:text="红色"                      android:textColor="@color/colorRed"                      android:textSize="32sp" />                    <RadioButton                      android:id="@+id/green_rbtn"                      android:layout_width="wrap_content"                      android:layout_height="wrap_content"                      android:text="绿色"                      android:textColor="@color/colorGreen"                      android:textSize="32sp" />                    <RadioButton                      android:id="@+id/purple_rbtn"                      android:layout_width="wrap_content"                      android:layout_height="wrap_content"                      android:text="紫色"                      android:textColor="@color/colorPurpleLight"                      android:textSize="32sp" />              </RadioGroup>            </LinearLayout>              <!-- 抽屉导航栏1 -->          <LinearLayout              android:id="@+id/left_drawer"              android:layout_width="400dp"              android:layout_height="300dp"              android:layout_gravity="start"              android:background="@color/colorPrimaryLight"              android:gravity="center"              android:orientation="vertical">                <TextView                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:text="左侧导航栏"                  android:textColor="@color/textPrimary"                  android:textSize="30sp" />                <Button                  android:id="@+id/close_start_drawer_btn"                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:text="关闭" />          </LinearLayout>            <!-- 抽屉导航栏2 -->          <RelativeLayout              android:id="@+id/right_drawer"              android:layout_width="wrap_content"              android:layout_height="match_parent"              android:layout_gravity="end"              android:background="@color/colorAccent">                <TextView                  android:layout_width="wrap_content"                  android:layout_height="wrap_content"                  android:layout_centerInParent="true"                  android:text="右侧导航栏"                  android:textColor="@color/textPrimary"                  android:textSize="30sp" />          </RelativeLayout>      </android.support.v4.widget.DrawerLayout>    </LinearLayout></code></pre>    <p>Activity.java</p>    <pre>  <code class="language-java">public class DrawerTestActivity extends AppCompatActivity {        @BindView(R.id.toolbar)      Toolbar toolbar;      @BindView(R.id.radio_group)      RadioGroup radioGroup;      @BindView(R.id.drawer_layout)      DrawerLayout drawerLayout;      @BindView(R.id.close_start_drawer_btn)      Button closeStartDrawerBtn;      @BindView(R.id.left_drawer)      LinearLayout leftDrawer;        private ActionBarDrawerToggle mToggle;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_drawer_test);          ButterKnife.bind(this);          setSupportActionBar(toolbar);            //配置ActionBarDrawerToggle          toggleSettings();            //配置RadioButton          scrimColorSettings();      }        private void toggleSettings() {          mToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);          drawerLayout.addDrawerListener(mToggle);          mToggle.syncState();      }        @Override      protected void onPostCreate(Bundle savedInstanceState) {          super.onPostCreate(savedInstanceState);          // Sync the toggle state after onRestoreInstanceState has occurred.          mToggle.syncState();      }        @Override      public void onConfigurationChanged(Configuration newConfig) {          super.onConfigurationChanged(newConfig);          mToggle.onConfigurationChanged(newConfig);      }          private void scrimColorSettings() {          radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {              @Override              public void onCheckedChanged(RadioGroup group, int checkedId) {                  switch (checkedId) {                      case R.id.red_rbtn:                          drawerLayout.setScrimColor(getResources().getColor(R.color.colorRed));                          break;                      case R.id.green_rbtn:                          drawerLayout.setScrimColor(getResources().getColor(R.color.colorGreen));                          break;                      case R.id.purple_rbtn:                          drawerLayout.setScrimColor(getResources().getColor(R.color.colorPurpleLight));                          break;                  }              }          });      }        @Override      public boolean onCreateOptionsMenu(Menu menu) {          getMenuInflater().inflate(R.menu.activity_drawer_test_menu, menu);          return super.onCreateOptionsMenu(menu);      }        @Override      public boolean onOptionsItemSelected(MenuItem item) {          // Pass the event to ActionBarDrawerToggle, if it returns          // true, then it has handled the app icon touch event          if (mToggle.onOptionsItemSelected(item)) {              return true;          }          switch (item.getItemId()) {              case R.id.action_drawers_close:                  drawerLayout.closeDrawers();                  break;              case R.id.action_drawer_locked_close:                  drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);                  break;              case R.id.action_drawer_locked_open:                  drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);                  break;              case R.id.action_drawer_unlocked:                  drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);                  break;              case R.id.action_drawer_reset:                  drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNDEFINED);                  break;          }          return super.onOptionsItemSelected(item);      }        @Override      public void onBackPressed() {          if (drawerLayout.isDrawerOpen(GravityCompat.START)) {              drawerLayout.closeDrawer(GravityCompat.START);          } else {              super.onBackPressed();          }      }        @OnClick(R.id.close_start_drawer_btn)      public void onClick() {          drawerLayout.closeDrawer(leftDrawer);      }  }</code></pre>    <h2><strong>NavigationView介绍</strong></h2>    <p style="text-align:center">我们已经知道了如何使用DrawerLayout在侧边弹出页面,接下来我们就要实现抽屉的具体效果了。那么在Material Design里,对抽屉的具体细节要求都是什么呢?看图... <img src="https://simg.open-open.com/show/29ad946124dabfe49b4d8804c059f18d.png"></p>    <p>有如此细节的要求,自然应该有个实现这些细节的组件配合。为此,Google提供了NavigationView组件,将NavigationView与Drawerlayout配合使用,我们便可以轻松实现抽屉菜单。</p>    <p>NavigationView可分为两部分——头部布局和菜单点击项布局。由于NavigationView使用比较简单和呆板,我决定尝试FAQ的方式来介绍这个组件的使用。</p>    <h2><strong>FAQ</strong></h2>    <ol>     <li>如何指定头布局和菜单点击项布局?<br> 答:可在XML布局里使用 <strong>app:headerLayout="@layout/layout文件"</strong> 来指定头布局,使用 <strong>app:menu="@menu/menu文件"</strong> 来指定菜单点击项;<br> 在Java代码里可以使用 <strong>inflateHeaderView(View view)</strong> 来指定头布局,使用 <strong>inflateMenu(int resId)</strong> 来指定菜单布局。</li>     <li>如何监听和处理菜单点击事件? <pre>  <code class="language-java">NavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {              @Override              public boolean onNavigationItemSelected(@NonNull MenuItem item) {                  //在此根据每个item的id处理相应的逻辑即可                  return true;              }          });</code></pre> </li>     <li>如何改变菜单中图标的颜色?<br> 答: <strong>app:itemIconTint="@color/颜色"</strong></li>     <li>如何让菜单中的图标颜色还原成原本真实的颜色?<br> 答: <strong> </strong> <p>NavigationView.setItemIconTintList(null)</p> </li>     <li>如何设置头部布局中的控件点击事件?<br> 答:首先,使用NavigationView <strong>.getHeaderView(0)</strong> 获得头部布局,然后使用该布局的findViewById()获取相应控件绑定点击事件即可。</li>    </ol>    <p>以上是使用NavigationView通常会遇到的问题,如果你还有其他的问题,欢迎在评论里交流。如果你还是对它的使用觉得云里雾里,那么看我最后的代码吧~:blush:</p>    <h2><strong>将DrawerLayout延伸至状态栏</strong></h2>    <p>这是一个引起过广泛讨论的问题,有关于这方面的文章和问题也有很多,当然也有不止一种解决方案,我采用的解决思路是:</p>    <ol>     <li>将状态栏设为透明</li>     <li>根据StatusBar的值为Toolbar设置相应的paddingTop</li>     <li>为作为根布局的DrawerLayout设置 <strong>setFitsSystemWindows(true)</strong></li>     <li>为作为根布局的Drawerlayout设置 <strong> </strong> <p>setClipToPadding(false)</p> </li>    </ol>    <p>具体实现和效果请看下面的代码示例。</p>    <h2><strong>代码示例(二)</strong></h2>    <p><strong>效果图(Android 4.4)</strong></p>    <p style="text-align:center"><strong><img src="https://simg.open-open.com/show/db890f867a829790fae50e41aaa1f132.png"> </strong></p>    <p><strong>效果图(Android 7.0) </strong></p>    <p><strong>5.0以上都一样,就不全放了。</strong></p>    <p style="text-align:center"><strong><img src="https://simg.open-open.com/show/e90f5953414fbf2c70a18f47f86ff775.jpg"> </strong></p>    <p><strong>layout.xml </strong></p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:app="http://schemas.android.com/apk/res-auto"      xmlns:tools="http://schemas.android.com/tools"      android:id="@+id/drawer_layout"      android:layout_width="match_parent"      android:layout_height="match_parent"      tools:openDrawer="start">        <include          layout="@layout/content_main"          android:layout_width="match_parent"          android:layout_height="match_parent" />        <android.support.design.widget.NavigationView          android:id="@+id/nav_view"          android:layout_width="wrap_content"          android:layout_height="match_parent"          android:layout_gravity="start"          android:background="@color/colorBlueGrey"          app:headerLayout="@layout/nav_header_drawer_demo"          app:itemBackground="@color/colorYellowLight"          app:itemIconTint="@color/colorRed"          app:itemTextColor="@color/colorGreen"          app:menu="@menu/activity_drawer_demo_drawer" />    </android.support.v4.widget.DrawerLayout></code></pre>    <p><br> <strong>content_main.xml </strong></p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:orientation="vertical">        <android.support.design.widget.AppBarLayout          android:layout_width="match_parent"          android:layout_height="wrap_content"          android:theme="@style/AppTheme.AppBarOverlay">            <android.support.v7.widget.Toolbar xmlns:app="http://schemas.android.com/apk/res-auto"              android:id="@+id/toolbar"              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:background="@color/colorPrimary"              android:minHeight="?actionBarSize"              android:paddingTop="@dimen/status_bar_height"              app:popupTheme="@style/ThemeOverlay.AppCompat.Light"              app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />        </android.support.design.widget.AppBarLayout>  </LinearLayout></code></pre>    <p><strong>这里的dimen根据v23来区分即可。</strong></p>    <p><strong>Activity.java </strong></p>    <pre>  <code class="language-java">public class DrawerDemoActivity extends AppCompatActivity          implements NavigationView.OnNavigationItemSelectedListener {        ActionBarDrawerToggle toggle;        @BindView(R.id.toolbar)      Toolbar toolbar;      @BindView(R.id.nav_view)      NavigationView navView;      @BindView(R.id.drawer_layout)      DrawerLayout drawerLayout;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_drawer_demo);          ButterKnife.bind(this);          setSupportActionBar(toolbar);            handlingStatusBar();          toggleSettings();          navView.setNavigationItemSelectedListener(this);        }        /**       * 说明:DrawerLayout延伸至StatusBar并正常显示       */      private void handlingStatusBar() {          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {              WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();              localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);                drawerLayout.setFitsSystemWindows(true);              drawerLayout.setClipToPadding(false);          }      }            /**       * 说明:配置ActionBarDrawerToggle       */      private void toggleSettings() {          toggle = new ActionBarDrawerToggle(                  this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);          drawerLayout.addDrawerListener(toggle);          toggle.syncState();      }          @Override      public void onBackPressed() {          DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);          if (drawer.isDrawerOpen(GravityCompat.START)) {              drawer.closeDrawer(GravityCompat.START);          } else {              super.onBackPressed();          }      }        @SuppressWarnings("StatementWithEmptyBody")      @Override      public boolean onNavigationItemSelected(MenuItem item) {          // Handle navigation view item clicks here.          int id = item.getItemId();            if (id == R.id.nav_camera) {            } else if (id == R.id.nav_gallery) {            } else if (id == R.id.nav_slideshow) {            } else if (id == R.id.nav_manage) {            } else if (id == R.id.nav_share) {            } else if (id == R.id.nav_send) {            }            drawerLayout.closeDrawer(GravityCompat.START);          return true;      }        @Override      protected void onPostCreate(Bundle savedInstanceState) {          super.onPostCreate(savedInstanceState);          // Sync the toggle state after onRestoreInstanceState has occurred.          toggle.syncState();      }        @Override      public void onConfigurationChanged(Configuration newConfig) {          super.onConfigurationChanged(newConfig);          toggle.onConfigurationChanged(newConfig);      }        @Override      public boolean onOptionsItemSelected(MenuItem item) {          // Pass the event to ActionBarDrawerToggle, if it returns          // true, then it has handled the app icon touch event          if (toggle.onOptionsItemSelected(item)) {              return true;          }          return super.onOptionsItemSelected(item);      }  }</code></pre>    <h2><strong>几句额外的</strong></h2>    <p>从Bottom Navigation加入MD规范开始,我就看到过有关“抛弃Drawer”的说法,最近又看到了几篇这样的文章。其中不乏一些好的思考,但有些观点还是过于激进了,甚至有些人云亦云。这里想分享下自己的看法:</p>    <p>首先,我们在 <strong>设计产品的时候,做出的一切决定都应该基于产品本身</strong> :当前页面的业务场景是什么,什么才是最符合需求的交互形式? <strong>至于组件和界面只是产品的呈现手段和方式,最终目的都是为了给出一个最符合需求的产品。</strong></p>    <p>再者,在学习和遵循Material Design时,除了知道怎么使用各种组件, <strong>更应该理解这些组件真正的作用是什么,设计思想是什么</strong> 。只有这样,我们才能在设计APP时做出更加正确的决定。 <strong>一个符合Material Design的APP绝不会是由各种MD组件随意堆砌而成的。</strong> 至于说到抛弃Drawer,我认为更是完全没有必要,不然你看看Android 7.0的设置界面?</p>    <p>下一篇我会介绍有关 <strong>Bottom Navigation</strong> 的知识点,也算是个对比。希望看完这两篇后,能够帮助你在构思界面时做出更好的决定。</p>    <h2><strong>参考文章</strong></h2>    <p><a href="/misc/goto?guid=4959724782456643618" rel="nofollow,noindex">Creating a Navigation Drawer | Android官方文档 </a></p>    <p><a href="/misc/goto?guid=4959724782540475269" rel="nofollow,noindex">DrawerLayout | Android官方文档 </a></p>    <p><a href="/misc/goto?guid=4959724782631964099" rel="nofollow,noindex">Why would I want to fitsSystemWindows? </a></p>    <p><a href="/misc/goto?guid=4959724782712382297" rel="nofollow,noindex">http:// weixin.qq.com/r/yTgrM-D ESK03rbRQ923b </a> (二维码自动识别)</p>    <p> </p>    <p> </p>    <p>来自:https://zhuanlan.zhihu.com/p/22970240</p>    <p> </p>