Android中的NavigationView
在本教程中,我们将在android应用程序中讨论和实现NavigationView。
其中我们将学习如何设置样式,使其也从右向左打开。
导航视图
在本教程中,我们已经实现了导航抽屉,并且编写代码很麻烦。
NavigationView是一种更好,更容易实现的导航抽屉替代品。
NavigationDrawer要求我们通过实现自定义适配器来使用ListView/RecyclerView实现项目。
引入NavigationView后,我们所要做的就是使用我们很快将看到的菜单资源来为项目充气。
NavigationView通常放置在DrawerLayout中。
NavigationView入门
Android Studio为我们提供了一个现成的导航抽屉活动,该活动实现了一个标准的导航菜单。
您可以从以下对话框中选择它。
了解NavigationView
NavigationView类扩展了FrameLayout。
在标记下的xml中定义为:
<android.support.design.widget.NavigationView
NavigationView本质上包含两个主要组件:
- HeaderView:此视图通常显示在导航抽屉的顶部。
它实际上包含个人资料图片,姓名电子邮件地址和背景封面图片。
此视图是在一个单独的布局文件中定义的,我们将稍后介绍。
要将布局添加到NavigationView中,请使用app:headerLayout参数 - 菜单:此菜单显示在HeaderView下方,并以列表形式包含所有导航项。
布局文件在menus文件夹中定义。
要将布局添加到NavigationView中,请使用app:menus参数
用于自定义NavigationView的其他重要XML属性是:
- app:itemTextColor:这会更改文本颜色
- app:itemIconTint:这会更改图标颜色
- app:itemBackground:这会更改项目背景颜色
让我们看一下内置的NavigationView模板的项目结构。
" activity_main.xml"是MainActivity的布局。
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_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:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"
</android.support.v4.widget.DrawerLayout>
注意:上面的DrawerLayout是用于保存导航抽屉内容和我们应用程序内容的布局。
app_bar_main.xml布局由一个包含工具列的CoordinatorLayout,一个FloatingActionButton和一个content_main.xml布局(显示一个基本的" Hello World" TextView)组成。
布局在下面列出。
app_bar_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.theitroad.navigationviewstyling.MainActivity">
<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
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main"
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email"
</android.support.design.widget.CoordinatorLayout>
content_main.xml的布局如下所示:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.theitroad.navigationviewstyling.MainActivity"
tools:showIn="@layout/app_bar_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
</RelativeLayout>
下面列出了默认的headerLayout和NavigationView的菜单:
nav_header_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:src="@android:drawable/sym_def_app_icon"
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="Android Studio"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="[email protected]"
</LinearLayout>
activity_main_drawer.xml
<menu xmlns:android="https://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_camera"
android:icon="@drawable/ic_menu_camera"
android:title="Import"
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="Gallery"
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_menu_slideshow"
android:title="Slideshow"
<item
android:id="@+id/nav_manage"
android:icon="@drawable/ic_menu_manage"
android:title="Tools"
</group>
<item android:title="Communicate">
<menu>
<item
android:id="@+id/nav_share"
android:icon="@drawable/ic_menu_share"
android:title="Share"
<item
android:id="@+id/nav_send"
android:icon="@drawable/ic_menu_send"
android:title="Send"
</menu>
</item>
</menu>
android:checkableBehavior xml属性是为整个组定义的,它采用下面列出的三个值之一。
- single:只能检查组中的一项
- all:可以选中所有项目(复选框)
- none:没有项目可检查
android:checkable属性用于设置单个项目的可检查行为。
它接受布尔值。
注意:在应用程序:菜单布局中可以使用嵌套菜单项
MainActivity.java在下面给出
package com.theitroad.navigationviewstyling;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.view.View;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
//drawer.setDrawerListener(toggle);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
//Handle action bar item clicks here. The action bar will
//automatically handle clicks on the Home/Up button, so long
//as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
//Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
//Handle the camera action
} 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 drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
从上面的代码中得出的重要推论如下:
MainActivity实现NavigationView.OnNavigationItemSelectedListener并覆盖onNavigationItemSelected方法。
我们在这里处理菜单项的单击,然后向左关闭抽屉。
让我们为每个项目显示一条Toast消息,如下所示。ActionBarDrawerToggle初始化为:
ActionBarDrawerToggle与DrawerLayout一起使用,以实现导航抽屉的推荐功能。
它具有以下用法:用作侦听器,用于打开和关闭抽屉。它在ToolBar/ActionBar中提供汉堡包图标。
允许在汉堡图标和箭头之间存在动画。
Note: android.support.v4.app.ActionBarDrawerToggle is deprecated. Always use android.support.v7.app.ActionBarDrawerToggle as a replacement.- 要在DrawerLayout上添加侦听器,请使用以下方法。
drawer.addDrawerListener(toggle);
该侦听器用于通知抽屉事件。
注意:现已弃用drawer.setDrawerListener(toggle)。
toggle.syncState():将同步图标的状态并显示汉堡图标或者后退箭头,具体取决于抽屉是关闭还是打开。
关闭抽屉时,省略这一行代码不会将后退箭头更改为汉堡包图标。cabinet.closeDrawer(GravityCompat.START):用于通过将重力设置为START来关闭抽屉(默认为左侧)
这是默认的NavigationView在应用程序中的外观:
请注意,最后单击的项目在第一个组中始终保持突出显示状态。
要在抽屉关闭后立即移除高亮显示,请将android:checkableBehavior更改为" none"。
当前的NavigationView绘制在状态列上。
要将其置于状态列下方,请将NavigationView的android:fitsSystemWindows设置为" false"。
现在,通过设置以上属性,我们可以通过在NavigationView中设置android:layout_marginTop =""?attr/actionBarSize"并将其设置在ToolBar/ActionBar(尽管在《材料设计准则》中不建议使用此样式)来进一步设置NavigationView的样式。
android:fitsSystemWindows =" false"用于CoordinatorLayout和DrawerLayout。
完成上述自定义后,这就是输出的样子:
您在顶部看到白色的状态列吗?这是因为将CoordinatorLayout和DrawerLayout的android:fitSystemWindows设置为false。
像@ color/colorPrimaryDark这样的styles.xml中的状态列样式不会改变。
我们需要更好的方法。
唯一的选择是摆脱CoordinatorLayout(我们也不使用它的动画),并将DrawerLayout和ToolBar放在LinearLayout中。
这是更新xml布局:
activity_main.xml
@Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_camera) {
//Handle the camera action
Toast.makeText(getApplicationContext(), "Camera is clicked", Toast.LENGTH_SHORT).show();
} else if (id == R.id.nav_gallery) {
Toast.makeText(getApplicationContext(), "Gallery is clicked", Toast.LENGTH_SHORT).show();
} else if (id == R.id.nav_slideshow) {
Toast.makeText(getApplicationContext(), "Slideshow is clicked", Toast.LENGTH_SHORT).show();
} else if (id == R.id.nav_manage) {
Toast.makeText(getApplicationContext(), "Tools is clicked", Toast.LENGTH_SHORT).show();
} else if (id == R.id.nav_share) {
Toast.makeText(getApplicationContext(), "Share is clicked", Toast.LENGTH_SHORT).show();
} else if (id == R.id.nav_send) {
Toast.makeText(getApplicationContext(), "Send is clicked", Toast.LENGTH_SHORT).show();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
工具列中需要android:fitSystemWindows =" true"。
省略它,您将得到类似这样的结果!
注意:移除xml属性android:theme =" @ style/AppTheme.AppBarOverlay"会将ToolBar项目颜色更改为黑色。
app_bar_main.xml
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
这就是应用程序现在的外观。
等一下!状态列颜色与工具列相同。
本来应该是暗一点的阴影。
解决方案:只需从v-21/styles.xml中删除以下行
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The toolbar -->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:minHeight="?attr/actionBarSize"
android:theme="@style/AppTheme.AppBarOverlay"
android:background="?attr/colorPrimary"
<android.support.v4.widget.DrawerLayout
xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="match_parent">
<include
layout="@layout/app_bar_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:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
让我们自定义NavigationView,使其从右向左打开!
项目结构
我们将自己的汉堡包图标png文件添加到drawable文件夹中,如下所示。
Android NavigationView示例代码
现在将activity_main.xml布局定义为
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.theitroad.navigationviewstyling.MainActivity">
<include layout="@layout/content_main"
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:src="@android:drawable/ic_dialog_email"
android:layout_alignParentBottom="true"
android:layout_margin="@dimen/activity_horizontal_margin"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
</RelativeLayout>
我们已将带有BarLayout的ToolBar放置在RelativeLayout内。
android:fitSystemWindows必须在所有三个中都设置为true。
DrawerLayout包含tools:openDrawer =" end""和android:layout_gravity =" end"",它们将抽屉的默认一侧更改为右侧。
理想情况下,圆形标题图像在NavigationView中看起来很漂亮。
我们将编译依赖项de.hdodenhof.circleimageview.CircleImageView,并在nav_header_main.xml文件中使用它,如下所示。
nav_header_main.xml
<item name="android:statusBarColor">@android:color/transparent</item>
其他xml布局与上面讨论的相同。
MainActivity.java在下面给出
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The toolbar -->
<RelativeLayout
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay"
<FrameLayout
android:id="@+id/drawer_button"
android:layout_width="50dp"
android:layout_height="?attr/actionBarSize"
android:fitsSystemWindows="true"
android:layout_alignParentRight="true"
android:clickable="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center_vertical"
android:src="@drawable/ic_action_not_black"
</FrameLayout>
</RelativeLayout>
<android.support.v4.widget.DrawerLayout
xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:layout_height="match_parent"
tools:openDrawer="end">
<include
layout="@layout/app_bar_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="end"
android:fitsSystemWindows="true"
app:itemTextColor="#1d3f4c"
app:itemIconTint="#cd4312"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
从以上代码得出的重要推论是:
toggle.setDrawerIndicatorEnabled(false);:此行用于隐藏显示在左侧的默认汉堡包图标。现在,所有GravityCompat常量都更改为END而不是START。

