(转)DrawerLayout +Navigation使用(防QQ侧滑)

(转   微信公众号: 码农专栏)


DrawerLayout 是 Support Library 包中实现了侧滑菜单效果的控件,可以说 DrawerLayout 是因为第三方控件如 MenuDrawer 等的出现之后,google 借鉴而出现的产物。DrawerLayout 分为侧边菜单和主内容区两部分,侧边菜单可以根据手势展开与隐藏(DrawerLayout 自身特性),主内容区的内容可以随着菜单的点击而变化。

一、DrawerLayout 基础使用

DrawerLayout 其实是一个布局控件,继承 ViewGroup,与 LinearLayout 等控件是一种东西,属于同级控件。但是 DrawerLayout 带有滑动的功能。只要按照 DrawerLayout 的规定布局方式写完布局,就能有侧滑的效果。

DrawerLayout 最简单的使用方式,添加 2 个子布局,分别代表 APP 主页面和侧滑菜单页面。

<?xml version="1.0" encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/drawerLayout"

android:layout_width="match_parent"

android:layout_height="match_parent">

<!--主页面-->

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="centerCrop"

android:src="@mipmap/meizi_2"/>

<!--侧滑菜单页面-->

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="centerCrop"

android:src="@mipmap/pangzi"/>

完成上面的布局文件,就可以实现如下效果:

二、DrawerLayout + ToolBar 使用

日常开发中,每个界面都会有一个 ToolBar,并且侧滑出来的内容都会在 ToolBar 的底部。最常见的就是 ToolBar 左侧会有一个小图标(号称三道杠),在侧滑菜单展示时,会加载一个动画变成返回按钮,完成这个效果不需要在 ToolBar 上自己添加 Icon,只需要借助 ActionBarDrawerToggle 类就可实现。

ActionBarDrawerToggle 效果就是一个“三“ 然后点击变”←“

ActionBarDrawerToggle 的作用:

改变 android.R.id.home 返回图标

DrawerLayout 拉出、隐藏,带有 android.R.id.home 动画效果

监听 DrawerLayout 拉出、隐藏

因为要实现侧滑菜单在 ToolBar 底部,修改 XML 文件,将 ToolBar 放在 DrawerLayout 布局外层。

<?xml version="1.0" encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/toolbar"

android:layout_width="match_parent"

android:layout_height="?attr/actionBarSize"

android:background="?attr/colorPrimary"

app:layout_scrollFlags="scroll|enterAlways"

app:title="DrawerLayout"

tools:ignore="MissingConstraints"/>

android:id="@+id/drawerLayout"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="centerCrop"

android:src="@mipmap/meizi_2"/>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="centerCrop"

android:src="@mipmap/pangzi"/>

// 设置左上角图标["三" —— "←"]效果

ActionBarDrawerToggle actionBarDrawerToggle =newActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);

actionBarDrawerToggle.syncState();

drawerLayout.addDrawerListener(actionBarDrawerToggle);

三、NavigationView 介绍

NavigationView 是 Google 在侧滑的 Material Design 的一种规范,所以提出了一个新的空间,用来规范侧滑菜单的基本样式。

对于抽屉式菜单界面很多 APP 都有应用,此前写抽屉式界面都需要自定义。现在谷歌提供的导航视图 NavigationView + DrawerLayout 结合使用,能提供很好的侧滑交互体验。

四、NavigationView 常用方法

方法介绍

addHeaderView(View view)将视图添加为导航菜单的标题

getHeaderCount()获取此 NavigationView 中标头的数量

getHeaderView(int index)获取指定位置的标题视图

getMenu()返回 Menu 与此导航视图关联的实例

inflateMenu(int resId)在此导航视图中添加菜单资源

removeHeaderView(View view)删除先前添加的标题视图

setItemBackgroundResource(int resId)将菜单项的背景设置为给定资源

setItemIconSize(int iconSize)设置用于菜单项图标的大小(以像素为单位)

setItemTextAppearance(int resId)将菜单项的文本外观设置为给定资源

setItemTextColor(ColorStateList textColor)设置要在菜单项上使用的文本颜色

setItemIconTintList(ColorStateList tint)设置菜单项上使用 Icon 的颜色

     setNavigationItemSelectedListener(NavigationView listener)                           设置一个侦听器,当选择菜单项时将用来通知该侦听器                     

五、NavigationView 基础使用

DrawerLayout + NavigationView + ToolBar 结合使用是项目中最常见的效果,通常有 2 种效果:

侧滑菜单在 ToolBar 底部

侧滑菜单沉浸式覆盖 ToolBar 展示

第一种效果实际上就是在 XML 布局中,将 ToolBar 布局放到 DrawerLayout 外部,第二种效果是将 ToolBar 放到 DrawerLayout 内部主页面布局里面,然后实现沉浸式效果。本文源码中有沉浸式实现的工具类,感兴趣的朋友可以下载源码参考

1、XML 布局文件

<?xml version="1.0" encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/drawerLayout"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:fitsSystemWindows="true">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/toolbar"

android:layout_width="match_parent"

android:layout_height="?attr/actionBarSize"

android:background="?attr/colorPrimary"

app:layout_scrollFlags="scroll|enterAlways"

app:title="DrawerLayout"

app:titleTextColor="#FFF"

tools:ignore="MissingConstraints"/>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="centerCrop"

android:src="@mipmap/meizi_2"/>

android:id="@+id/navigationView"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_gravity="start"

app:headerLayout="@layout/nav_header_main"

app:insetForeground="@android:color/transparent"

app:menu="@menu/activity_main_drawer"/>

只需在 DrawerLayout 中添加 NavigationView 控件即可,其中介绍两个属性(也就是上图中红黄蓝三个位置效果):

app:insetForeground="@android:color/transparent" NavigationView 沉浸式展示

app:headerLayout="@layout/nav_header_main" 在 NavigationView 上添加一个 Header 布局

app:menu="@menu/activity_main_drawer" NavigationView 添加标签 Item 的菜单

2、HeaderLayout 布局文件

<?xml version="1.0" encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="200dp"

android:background="?attr/colorPrimary"

android:gravity="bottom"

android:theme="@style/ThemeOverlay.AppCompat.Dark">

android:id="@+id/movingImageView"

android:layout_width="match_parent"

android:layout_height="250dp"

android:scaleType="centerCrop"

android:src="@mipmap/menu_header_background"

app:miv_load_on_create="false"

app:miv_max_relative_size="3.0"

app:miv_min_relative_offset="0.2"

app:miv_repetitions="-1"

app:miv_speed="100"

app:miv_start_delay="100"/>

android:layout_width="100dp"

android:layout_height="100dp"

android:layout_marginLeft="16dp"

android:layout_marginTop="30dp"

android:paddingTop="16dp"

android:src="@mipmap/header_icon"

app:civ_border_color="@color/colorWhite"

app:civ_border_width="2dp"/>

android:id="@+id/tv_nick"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_gravity="bottom"

android:layout_marginLeft="16dp"

android:layout_marginTop="10dp"

android:layout_marginBottom="16dp"

android:paddingLeft="5dp"

android:text="Learn and live."

android:textAppearance="@style/TextAppearance.AppCompat.Body1"

android:textSize="18sp"/>

3、Menu 菜单文件

这里的 icon 图标全部使用 vector 矢量图展示,如果还不会使用 Vector 矢量图的朋友,可以参考:

Android Material Design Icon Genenerator 插件为个人开发者提供 Icon 图标大全

<?xml version="1.0" encoding="utf-8"?>

android:id="@+id/group_item_github"

android:icon="@drawable/ic_vector_github_grey"

android:title="项目主页"/>

android:id="@+id/group_item_more"

android:icon="@drawable/ic_vector_more"

android:title="更多内容"/>

android:id="@+id/group_item_qr_code"

android:icon="@drawable/ic_vector_qr_code"

android:title="二维码"/>

android:id="@+id/group_item_share_project"

android:icon="@drawable/ic_vector_share"

android:title="分享项目"/>

android:id="@+id/item_model"

android:icon="@drawable/ic_vetor_setting"

android:title="夜间模式"/>

android:id="@+id/item_about"

android:icon="@drawable/ic_vector_about"

android:title="关于"/>

4、Activity 代码实现

NavigationView 的使用基本上都是 XML 文件中完成的,Activity 中不需要做太多处理,只需要 Activity 中添加 Menu 的监听。本项目中使用了一个带动画的 ImageView,所以侧滑菜单后,底部图片会有动画效果,感兴趣的可以在底部下载源码学习。

publicclassDrawerLayoutActivityextendsBaseActivity{

@BindView(R.id.toolbar)

Toolbar toolbar;

@BindView(R.id.drawerLayout)

DrawerLayout drawerLayout;

@BindView(R.id.navigationView)

NavigationView navigationView;

MovingImageView movingImageView;

privateActionBarDrawerToggle actionBarDrawerToggle;

@Override

protectedvoidinitView(){

movingImageView = navigationView.getHeaderView(0).findViewById(R.id.movingImageView);

// 设置左上角图标["三" —— "←"]效果

actionBarDrawerToggle =newActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);

actionBarDrawerToggle.syncState();

drawerLayout.addDrawerListener(actionBarDrawerToggle);

// 设置不允许 NavigationMenuView 滚动

NavigationMenuView navigationMenuView = (NavigationMenuView) navigationView.getChildAt(0);

if(navigationMenuView !=null) {

navigationMenuView.setVerticalScrollBarEnabled(false);

}

// NavigationView 监听

navigationView.setNavigationItemSelectedListener(newNavigationView.OnNavigationItemSelectedListener() {

@Override

publicbooleanonNavigationItemSelected(@NonNull MenuItem item){

switch(item.getItemId()) {

caseR.id.group_item_github:

Toast.makeText(DrawerLayoutActivity.this,"项目主页",Toast.LENGTH_SHORT).show();

break;

caseR.id.group_item_more:

Toast.makeText(DrawerLayoutActivity.this,"更多内容",Toast.LENGTH_SHORT).show();

break;

caseR.id.group_item_qr_code:

Toast.makeText(DrawerLayoutActivity.this,"二维码",Toast.LENGTH_SHORT).show();

break;

caseR.id.group_item_share_project:

Toast.makeText(DrawerLayoutActivity.this,"分享项目",Toast.LENGTH_SHORT).show();

break;

caseR.id.item_model:

Toast.makeText(DrawerLayoutActivity.this,"夜间模式",Toast.LENGTH_SHORT).show();

break;

caseR.id.item_about:

Toast.makeText(DrawerLayoutActivity.this,"关于",Toast.LENGTH_SHORT).show();

break;

}

item.setCheckable(false);

drawerLayout.closeDrawer(GravityCompat.START);

returntrue;

}

});

}

@Override

protectedintgetLayoutResID(){

returnR.layout.activity_drawerlayout;

}

}

六、NavigationView 全屏效果

1、设置全屏显示

NavigationView 设置 android:layout_width="match_parent" 发现仍然无法实现全屏展示效果,如果想要 NavigationView 实现全屏展示,代码中按照如下设置:

ViewGroup.LayoutParams mLayoutParams = navigationView.getLayoutParams();

intwidth = getResources().getDisplayMetrics().widthPixels;

mLayoutParams.width = width;

navigationView.setLayoutParams(mLayoutParams);

2、仿 QQ 侧滑菜单效果

根据 NavigationView 全屏效果,模仿 QQ 个人中心侧滑菜单效果,其实我们发现 QQ 这么牛逼的软件,也是使用 Google 原生控件实现,可想而知 Material Design 系列控件之强大。QQ 侧滑菜单实现由以下两点组成:

QQ 侧滑菜单铺满全屏

主页面跟随菜单一起滑动

第一点我们已经实现,只需要上面 4 行代码就可以设置 NavigationView 全屏效果,接下来只需要将主页面跟随菜单一起滑动就可以实现效果,我们回想前面讲到的 DrawerLayout.addDrawerListener() 方法,可以监听事件,其中有 4 个回调方法:

onDrawerSlide(View drawerView, float slideOffset) 当抽屉的位置改变时调用

onDrawerOpened(View drawerView) 打开侧滑界面触发

onDrawerClosed(View drawerView) 关闭侧滑界面触发

onDrawerStateChanged(int newState) 状态改变时触发

根据上面 4 个回调方法,要实现 QQ 效果,需要在 onDrawerSlide(View drawerView, float slideOffset) 方法中进行处理,其中 slideOffset 返回的是抽屉菜单从隐藏到打开的偏移,取值 0~1,drawerView 就是侧边菜单布局,具体实现代码如下:

<?xml version="1.0" encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

android:id="@+id/drawerLayout"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scaleType="centerCrop"

android:src="@mipmap/qq_1"/>

android:id="@+id/navigationView"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_gravity="start"

app:headerLayout="@layout/nav_header_main"

app:insetForeground="@android:color/transparent"

app:menu="@menu/activity_main_drawer"/>

drawerLayout.addDrawerListener(newDrawerLayout.DrawerListener() {

@Override

publicvoidonDrawerSlide(@NonNull View drawerView,floatslideOffset){

// 主页内容

View contentView = drawerLayout.getChildAt(0);

// 侧边栏

View menuView = drawerView;

// slideOffset 值默认是0~1

contentView.setTranslationX(menuView.getMeasuredWidth() * slideOffset);

}

@Override

publicvoidonDrawerOpened(@NonNull View drawerView){}

@Override

publicvoidonDrawerClosed(@NonNull View drawerView){}

@Override

publicvoidonDrawerStateChanged(intnewState){}

});

提示:仿 QQ 侧滑菜单效果,这里没有使用 ToolBar,直接截取了 2 张图片展示。

七、手动控制菜单

默认手势侧滑就可以 Open 菜单,点击空白处 Close。但是避免需要点击事件触发菜单状态,DrawerLayout 设计非常人性化,提供了以下方法来实现:

openDrawer(View drawerView)

打开指定的折叠项视图,将其动画到视图中。

closeDrawer(View drawerView)

关闭指定的折叠项视图,将其动画到视图中。

closeDrawers()

关闭所有当前打开的抽屉视图,通过动画他们的视野。

使用举例:

// 打开左边菜单

mDrawerLayout.openDrawer(GravityCompat.START);

// 打开右边菜单

mDrawerLayout.openDrawer(GravityCompat.END);

// 关闭左边菜单6

mDrawerLayout.closeDrawer(GravityCompat.START);

// 关闭所有菜单

mDrawerLayout.closeDrawers();

源码下载:https://github.com/jaynm888/MaterialDesign-master.git

源码包含 Material Design 系列控件集合,定时更新,敬请期待!

八、总结

Android Material Design Library 推出了很长时间,越来越多的 APP 使用了符合 Library 包的控件,DrawerLayout 绝对是热门之一,Material Design 定义了一个抽屉导航应该有何种外观和感受,统一了侧滑菜单和样式。在 Android 原生手机上对 DrawerLayout+NavigationView 更是使用到了极致。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353