ToolBar+DrawerLayout+NavigationView实现滑动菜单效果
- 引言:Google新推出的界面设计语言–Material Design使得我们在针对android的界面UI开发上省力了不少,它涵盖了许许多多的优秀控件以及设计,本篇博客介绍了其中的几个控件组合实现滑动菜单栏的效果,下面就一起来看看吧。
1.ToolBar的相关设置
1.ToolBar的概念
Toolbar是Material Design所建议使用的顶部导航栏控件,用以取代以前的ActionBar。相对于ActionBar而言,ToolBar在使用上更加的灵活,不仅可以实现与ActionBar完全相似的效果,还可以使我们对顶部导航栏进行统一的设计与管理,从而定制一些个性化的导航栏,大大增加了灵活性。那么接下来就让我们看看如何去使用它。
2.ToolBar的引入
在引入ToolBar之前,需要对我们的Activity主题进行设置。在默认的情况下,我们的Activity是采用的ActionBar来作为导航栏布局的,那么我们去到项目的资源路径下,找到style.xml
查看此时所采用的默认布局,下面是我的默认布局:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 <resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
```
那么,为了替换为ToolBar控件,就需要禁用掉相关的ActionBar,所以我们改变系统的默认主题,从而完成对ActionBar的禁用操作。替换主题如下:
```java
<resources>
<!-- Base application theme. -->
//只需要替换为"NoActionBar即可"
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
接下来,我们就可以在主Activity布局中,引入ToolBar控件,如下所示:
1 | <RelativeLayout |
到了这一步,我们的导航栏控件就引入成功了,那么,上述的ToolBar控件中的相关参数究竟都代表了什么意思呢?
height设置的意思是ToolBar的高度与系统的ActionBar的默认高度一致
background设置了toolbar的背景色为系统的主色调
在上面的时候,我们设置的主题是浅色系的风格,在这种风格下,ToolBar中的内容为了与背景作区分,将会显示为深色系,例如字体变黑色,显得比较难看,为了使其显示出与我们的总体布局相符合的状态,我们需要对其进行单独设置。一来要将ToolBar设置为深色系,二来将其中的内容(比如菜单项)设置为浅色系,这就是上述的两行主题设置的原因。
显示的效果如下:

2.DrawerLayout的相关设置
1.DrawerLayout的概念
DrawerLayout是谷歌推出的一款滑动布局,利用它我们可以很轻松地实现非常炫酷的滑动菜单效果。在以前,要实现滑动菜单效果,我们不仅需要去设计布局,更要计算菜单滑动出来的距离以及检测手势控制,可谓十分麻烦。而现在,这些都不需要了,我们只需要引入DrawerLayout布局,就能够完成滑动效果。那么,接下来我们看看如何去实现。
2.DrawerLayout的实现
//这里使用DrawerLayout作为根布局
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/drawer_layout"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:openDrawer="start">
//这是主视图布局
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray"
>
//引入ToolBar
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:layout_alignParentTop="true"
>
</android.support.v7.widget.Toolbar>
</RelativeLayout>
//这是侧滑栏布局
<TextView
android:layout_width="400dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:text="这里是侧滑栏中的内容"
android:textSize="25sp"
android:background="@color/colorAccent"
/>
</android.support.v4.widget.DrawerLayout>
代码如上所示:可以看到在这里我们将DrawerLayout作为了根布局进行使用,这是因为如果它作为子布局的话,可能会出现一些滑动上面的问题,因此,建议作为根布局使用。在它的里面,其实分为了两大块,一个是我们进入后所看到的主界面布局(即代码中的RelativeLayout布局),一个是我们的侧滑栏中的布局(TextView布局)。而这两块的区分,是依据我们在布局文件中的控件顺序决定的(先调用的将作为页面的主体布局)。下面针对DrawerLayout布局中的特殊属性作一个说明:
DrawerLayout根布局中的openDrawer属性,表明了我们想要让侧滑栏从哪边划出,可设置为左、右以及自动,自动表明由系统判断,中文左划,需要从右读起的语言则会默认右划。
另一个地方就是我们第二个控件布局(即作为侧滑栏的控件)需要设置一下划出方式,设置的方式是设定其layout_gravity
属性,”start“表示左划,以此类推。
此时,我们的侧滑栏就已经可以展现出来了,效果如下图所示:

现在还有两个问题,一是我们发现左边是否有侧滑栏我们虽然知道,但是用户却并不知情,为了让用户了解到我们的界面拥有侧滑效果,我们需要在我们的
ToolBar
上,显示一个图标并与我们的侧滑栏绑定起来,这样用户就可以知道我们是带有侧滑栏的;二是我们虽然实现了侧滑的效果,但是可以看到,侧滑栏中的界面是很丑陋的,为此,我们需要引入NavigationVIew来填充我们的DrawLayout,从而使其变得漂亮美观。那么,接下来,我们就先解决第一个问题。
3.DrawerLayout与ToolBar的绑定
ToolBar导航栏的最左侧,有一个名为HomeAsUp
的控件,它的默认图标是一个小箭头,作用是用来返回到上一层活动,我们的思路就是将它的HomeAsUp
控件图标和功能都进行改写,从而让它与NavigationView关联起来。具体做法如下,上代码:
/**
* 设置视图
*/
private void initView() {
//获取并设置Toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//获取总视图
mDrawerLayout = findViewById(R.id.drawer_layout);
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle("我是ToolBar");
if(actionBar!=null){
//设置HomeAsUp控件显示
actionBar.setDisplayHomeAsUpEnabled(true);
//变更HomeAsUp控件的图片
actionBar.setHomeAsUpIndicator(R.mipmap.icon);
}
}
/**
* 监测ToolBar的点击事件
*/
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
//android.R.id.Home作为HomeAsUp控件的id是不变的
case android.R.id.home:
//监测到点击事件时打开DrawerLayout
mDrawerLayout.openDrawer(GravityCompat.START);
break;
}
return true;
}
此时,我们就实现了点击ToolBar左上角的提示图标,展开DrawerLayout的操作。如下图所示:

3.NavigationView的相关设置
1.NavigationView的概念
NavigationView即导航布局,其使用场景大多就是结合DrawerLayout来实现比较炫酷的导航菜单栏的效果,我们还需要结合菜单布局,头布局,来一起完成最终的展示。不过不用着急,接下来我们就用代码去慢慢实现这个过程。
2.NavigationView的实现
首先是布局的引入,如下面所示,此时一定得注意,我们的这个布局是作为侧滑栏中的布局去填充的,因此,需要将其放在主布局的下面,作为第二个布局去使用。主布局代码如下:
//根布局自然是DrawerLayout了
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/drawer_layout"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:openDrawer="start">
//主布局相关视图
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray"
>
//这里是我们定义的ToolBar
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
android:layout_alignParentTop="true"
>
</android.support.v7.widget.Toolbar>
</RelativeLayout>
//引入到DrawerLayout中去的NavigationView视图控件
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="400dp"
android:layout_height="match_parent"
android:layout_gravity = "start"
//这里需要引入菜单布局
app:menu="@menu/nav_menu"
//这里引入头布局实现头布局效果
app:headerLayout="@layout/nav_header"
>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
主布局的任务到这里就结束了,下来是我们的头布局,主要作用是用来给侧滑栏单独定制一个头部的布局,我们看看布局代码nav_header.xml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"
android:padding="10dp"
android:background="?attr/colorPrimary"
>
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/icon_image"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="@mipmap/cat_head"
android:layout_centerInParent="true"
/>
<TextView
android:id="@+id/head_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/icon_image"
android:layout_marginTop="10dp"
android:layout_centerInParent="true"
android:textColor="#FFF"
android:textSize="20sp"
android:text="小猫"
/>
</RelativeLayout>
头布局里导入了一个图片处理库CircleImageView,其作用就是实现了将图片的形状转换为圆形的、类似头像的效果(最好是正方形的图)。
再就是最后一个,也就是我们的菜单栏布局:nav_menu.xml
,其实现了菜单栏中的各项数据的图片信息以及名称等,如下所示:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
//此属性为了保证菜单栏各个Item子项均处于单选状态
<group android:checkableBehavior="single">
<!--订单-->
<item android:id="@+id/nav_order"
android:icon="@mipmap/order"
android:title="我的订单"/>
<!--个人信息-->
<item android:id="@+id/nav_identity"
android:icon="@mipmap/identity"
android:title="个人信息"/>
<!--设置-->
<item android:id="@+id/nav_setting"
android:icon="@mipmap/setting"
android:title="相关设置"/>
</group>
</menu>
在这里我们需要注意,建立菜单栏的布局文件时,我们首先需要在res
资源文件夹下新创建menu
文件夹,这个文件夹不能通过New→Directory去建立,而是应该通过New→Android Resource Directory→Resource Type→menu去建立一个menu的资源文件夹,然后在里面建立资源型xml文件nav_menu.xml
这样才能成功创建。
最后,让我们在项目模块的build.gradle中,实现对图片处理库的引用,以及对NavigationView的引用:
//NavigationView控件相关包
compile 'com.android.support:design:26.1.0'
compile 'com.android.support:appcompat-v7:26.1.0'
//头像圆角化相关
compile 'de.hdodenhof:circleimageview:2.1.0'
大功告成,让我们看看现在的效果吧:

到这里,我们的功能算是实现了。最后,有两个小的知识点需要总结一下:
1.如何实现对NavigationView中的子项Item添加监听:
//设置菜单选中监听器,关闭侧滑栏
//获取侧滑栏
NavigationView navView = findViewById(R.id.nav_view);
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
mDrawerLayout.closeDrawers();
switch (item.getItemId()){
//监听菜单中各子项定义的ID即可
case R.id.nav_order:
break;
case R.id.nav_identity:
break;
}
return true;
}
});
2.如何实现对头布局中的控件进行监听(注:若在此处刷出头布局,则在布局文件中无需设置对头布局文件的引用):
//用NavView去得到其头布局视图
View view = navView.inflateHeaderView(R.layout.nav_header);
//获取姓名控件
naviName = view.findViewById(R.id.head_name);
好了,这篇博客就写到这里,后期会继续总结一些Material Design中比较炫酷的控件实现,敬请期待。