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。