一、 DrawerLayout
DrawerLayout官网教程
DrawerLayout官网API
在很多应用中都会有抽屉式导航栏,鉴于此,谷歌就提供了DrawerLayout来实现这个功能.
DrawerLayout在v4包中,使用时需要导入v4包,使用eclipse创建项目会自动导入v4包,使用studio创建项目时会自动添加v7依赖,v7是兼容v4的,所以直接用就是了......
1、 DrawerLayout的简单使用
DrawerLayout的使用非常简单,只要遵循几个规则就行了
布局文件:
<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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="主页面" />
</RelativeLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@android:color/holo_blue_dark"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:scrollbars="none" />
</android.support.v4.widget.DrawerLayout>
直接使用DrawerLayout作为根标签,然后DrawerLayout根据android:layout_gravity属性判断哪个是侧滑面板,使用start/end或者left/right来表明是抽屉式导航栏是左边的还是右边的,没有android:layout_gravity属性的就是主页面视图了.
ok,简单的侧滑效果完成了,就是这么简单,来看一下效果图:
是不是很简单,官网介绍了使用DrawerLayout的几条规范:
1、DrawerLayout最好声明为根标签
2、在DrawerLayout中,主页面视图(上面的 TextView那一部分,当然,这个内容是你自己决定的,不一定要是TextView)必须是第一个子视图
3、主页面视图设置为匹配父视图的宽度和高度, 因为在抽屉式导航栏处于隐藏状态时, 它代表整个 UI
4、抽屉式导航栏视图 必须使用 android:layout_gravity属性指定。
如果要支持“从右到左”(RTL) 语言,请使用 "start"(而非"left")指定该值(这样当布局为 RTL 时,抽屉式导航栏会显示在右侧)。
PS:RTL就是从右到左(Right To Left)的布局,我们在手机上/设置/开发者选项中有一个强制使用从右到左的布局方向,可以打开试一试效果.
虽然我们国内app一般都是从左到右,但我们还是听谷歌的建议比较好,使用start/end而非left/right.
5、抽屉式导航栏视图以 dp 为单位指定其宽度, 且高度与父视图相匹配。抽屉式导航栏的宽度不应超过 320dp,从而用户始终可以看到部分主内容。
2、 抽屉的数据填充
抽屉其实只是一个普通的View,这里我放的是ListView,看起来就像菜单,当然,你完全可以只放一个ImageView、TextView等等。这和Activity的菜单不一样,Activity的菜单只需要在资源文件中定义好,就能按照固定的形式显示出来。而DrawerLayout的侧边菜单显示成什么样完全是取决于你自己,同样点击菜单之后的逻辑也完全由你自己去写。
接下来给菜单填充数据
布局文件
<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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="主页面" />
<Button
android:id="@+id/bt_open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="打开" />
</RelativeLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@android:color/holo_blue_dark"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:scrollbars="none" />
</android.support.v4.widget.DrawerLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private List<String> mDatas;
private DrawerLayout mDrawerLayout;
private ListView mListView;
private TextView tvMain;
private Button btOpen;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
mListView.setAdapter(new ArrayAdapter<>(MainActivity.this,android.R.layout.simple_list_item_1,mDatas));
/**
* 点击菜单条目更改主界面TextView内容,同时关闭菜单
* 关闭菜单使用DrawerLayout.closeDrawer()方法,传入要关闭的菜单View或者菜单的方向都可以
*/
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
tvMain.setText(mDatas.get(position));
mDrawerLayout.closeDrawer(mListView);
// mDrawerLayout.closeDrawer(GravityCompat.START);
}
});
/**
* 打开菜单使用DrawerLayout.openDrawer()方法,传入要关闭的菜单View或者菜单的方向都可以
*/
btOpen.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mDrawerLayout.openDrawer(GravityCompat.START);
// mDrawerLayout.openDrawer(mListView);
}
});
}
private void initView() {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mListView = (ListView) findViewById(R.id.list_view);
tvMain = (TextView) findViewById(R.id.tv_main);
btOpen = (Button) findViewById(R.id.bt_open);
}
private void initData() {
mDatas = new ArrayList<>();
for (int i = 'A'; i < 'Z'; i++) {
mDatas.add("" + (char) i);
}
}
}
效果图
实际开发中这里的主页面视图一般用FrameLayout代替,点击菜单条目,动态为FrameLayout添加内容.
ok,简单的介绍了DrawerLayout的使用,接下来来看一下我们今天的主角
二、NavigationView
1、NavigationView是什么
NavigationView就是菜单View,也就是上面我们使用的ListView那一部分。
那么,有了DrawerLayout之后为什么还会出现一个NavigationView,看下面这张图:
这种效果的菜单用ListView或者RecyclerView也能实现,不过总要花点时间吧,但是用NavigationView之后简直分分钟搞定.
2、NavigationView的使用
(1)简单使用
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="主页面" />
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/header"
app:menu="@menu/main">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
NavigationView就是菜单面板,其中最重要的两条属性就是:
1、这就是菜单面板的头布局,也就是刚才头像,昵称那一栏,引用了一个布局文件
app:headerLayout="@layout/header"
header.xml
<?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="150dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="144dp"
android:layout_height="90dp"
android:layout_marginTop="10dp"
android:background="@mipmap/icon" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="随风飘扬的smile"
android:textColor="@android:color/white"
android:textSize="15sp" />
</LinearLayout>
2、这就是菜单面板的内容部分,也就是会员特权、XX钱包...那一部分,定义在res/menu/main.xml中
app:menu="@menu/main"
main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="会员特权" />
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX钱包" />
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="个性装扮" />
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相册" />
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="设置" />
</menu>
header和item部分内容都是根据实际需要来设置的.
(2)效果图:
效果有点不一样,没有了分隔线,而且图片都是灰灰的。
(3)添加分隔线:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="会员特权" />
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX钱包" />
</group>
<group android:id="@+id/group3">
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="个性装扮" />
</group>
<group android:id="@+id/group4">
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
</group>
<group android:id="@+id/group5">
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相册" />
</group>
<group android:id="@+id/group6">
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="设置" />
</group>
</menu>
在菜单条目文件中给item分组,就可以添加分隔线了。
再来看效果图:
ok!
(4)解决图片变灰问题:
方式1:你可以为NavigationView设置下面这条属性,不过那样item图片只能是统一的颜色
app:itemIconTint=""
方式2:Activity中代码设置,这样能让图片恢复原样了
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mNavigationView.setItemIconTintList(null);
ok,现在效果图和刚开始那张图完全一样了。
(5)item继续添加分组:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="会员特权" />
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX钱包" />
</group>
<group android:id="@+id/group3">
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="个性装扮" />
</group>
<group android:id="@+id/group4">
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
</group>
<group android:id="@+id/group5">
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相册" />
</group>
<group android:id="@+id/group6">
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="设置" />
</group>
<group android:id="@+id/group7">
<item
android:id="@+id/item_7"
android:icon="@mipmap/f"
android:title="其它" >
<menu>
<item
android:id="@+id/item_8"
android:icon="@mipmap/f"
android:title="分享" />
<item
android:id="@+id/item_9"
android:icon="@mipmap/f"
android:title="隐私" />
</menu>
</item>
</group>
</menu>
效果图:
当item过多会出现滚动条,如果要隐藏滚动条,给NavigationView设置android:scrollbars="none"是不管用的,因为这个滚动条不是NavigationView的,而是菜单的·.
可以在Activity中找到菜单View,然后取消滚动条
NavigationMenuView menuView = (NavigationMenuView) mNavigationView.getChildAt(0);
menuView.setVerticalScrollBarEnabled(false);
3、NavigationView其它属性
给菜单item部分添加背景
app:itemBackground=" "
给菜单item文字设置颜色
app:itemTextColor=" "
更多文字特效可以通过下面这条属性设置:
app:itemTextAppearance=" "
4、菜单item的一些属性
设定一组菜单项可以选中几个item,none、single、all三个值
<group android:id="@+id/group1" android:checkableBehavior="single">
菜单项 item 是否被选中,如果要默认选中一个菜单 item 则设为true
<item android:checked="true" />
5、NavigationView点击事件
(1)头部点击事件
headerView = mNavigationView.getHeaderView(0);
headerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"headerView",Toast.LENGTH_SHORT).show();
}
});
找到headerView ,然后设置点击事件即可
(2)头部控件点击事件
通过headerView.findViewById()找到要点击的控件,然后设置点击事件即可
ivIcon = (ImageView) headerView.findViewById(R.id.icon);
tvName = (TextView) headerView.findViewById(R.id.name);
ivIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"icon",Toast.LENGTH_SHORT).show();
}
});
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"name",Toast.LENGTH_SHORT).show();
}
});
(3)item点击事件
通过NavigationView.setNavigationItemSelectedListener()设置监听即可
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.item_1:
//do something
break;
case R.id.item_2:
//do something
break;
//......
}
return false;
}
});
(4)隐藏菜单某部分item
有时候可能会有些奇葩的需求,要求我们隐藏一些菜单item,满足一定条件才会显示出来.
MenuItem item = mNavigationView.getMenu().findItem(R.id.item_1);//找到要隐藏的item
item.setVisible(false);//false即隐藏,true即显示
三、 完整代码
Activity布局文件:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="主页面" />
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="left"
app:itemTextColor="@color/colorPrimaryDark"
app:headerLayout="@layout/header"
app:menu="@menu/main">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
header布局文件:
<?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="150dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/icon"
android:layout_width="144dp"
android:layout_height="90dp"
android:layout_marginTop="10dp"
android:background="@mipmap/icon" />
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="随风飘扬的smile"
android:textColor="@android:color/white"
android:textSize="15sp" />
</LinearLayout>
菜单文件
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="会员特权" />
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX钱包" />
</group>
<group android:id="@+id/group3">
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="个性装扮" />
</group>
<group android:id="@+id/group4">
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
</group>
<group android:id="@+id/group5">
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相册" />
</group>
<group android:id="@+id/group6">
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="设置" />
</group>
<group android:id="@+id/group7">
<item
android:id="@+id/item_7"
android:icon="@mipmap/f"
android:title="其它">
<menu>
<item
android:id="@+id/item_8"
android:icon="@mipmap/f"
android:title="分享" />
<item
android:id="@+id/item_9"
android:icon="@mipmap/f"
android:title="隐私" />
</menu>
</item>
</group>
</menu>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
private TextView tvMain;
private NavigationView mNavigationView;
private View headerView;
private ImageView ivIcon;
private TextView tvName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
tvMain = (TextView) findViewById(R.id.tv_main);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mNavigationView.setItemIconTintList(null);//让菜单item图片正常
// 隐藏菜单item
// MenuItem item = mNavigationView.getMenu().findItem(R.id.item_1);
// item.setVisible(false);
/**
* 隐藏滚动条
*/
NavigationMenuView menuView = (NavigationMenuView) mNavigationView.getChildAt(0);
menuView.setVerticalScrollBarEnabled(false);
/**
* header点击事件
*/
headerView = mNavigationView.getHeaderView(0);
headerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"headerView",Toast.LENGTH_SHORT).show();
}
});
/**
* headerView中组件点击事件
*/
ivIcon = (ImageView) headerView.findViewById(R.id.icon);
tvName = (TextView) headerView.findViewById(R.id.name);
ivIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"icon",Toast.LENGTH_SHORT).show();
}
});
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"name",Toast.LENGTH_SHORT).show();
}
});
/**
* 菜单item点击事件
*/
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.item_1:
//do something
break;
case R.id.item_2:
//do something
break;
//......
}
return false;
}
});
}
}
效果图