(1) MainActivity.java
(2) activity_main_drawer.xml
(3) nav_header_main.xml
(4) content_main.xml
(5) app_bar_main.xml
(6) activity_main.xml
下面我们一一说明以上几个文件,先从最简单的开始。
这个文件位于res-menu文件夹下,看位置就知道这是一个菜单文件,其中包含有一些菜单项,用来实现侧滑栏的菜单,显示如下所示:
下面我们来看内部的代码(说明全部写在代码中间了~~~)
xml version="1.0"encoding="utf-8"?>
<menuxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<groupandroid: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>
<itemandroid: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>
以上就是关于menu的说明;
这个文件位于res-layout下,是导航侧栏头部的布局文件,显示如下:
下面来看内部的代码,因为这一块比较简单,就在此稍微说明一下,不在代码中间详细介绍了。这个界面由一个垂直的线性布局构成,从上到下分别是ImageView和两个TextView,在实际开发的时候,可以在此进行自己的个性化设计,非常方便。代码贴在下面:
xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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"
app:srcCompat="@mipmap/ic_launcher_round"/>
<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>
这个布局文件构成主界面显示的内容,默认的情况下是一个TextView,当然在此可以进行个性化设计,默认的效果如下(除了右下角的悬浮按钮,一会儿说明);
下面对文件内部代码进行说明:
xml version="1.0"encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.dzjin.drawer.myapplication.MainActivity"
tools:showIn="@layout/app_bar_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
android.support.constraint.ConstraintLayout>
这个界面也比较简单,不过多解释说明。
这是一个比较复杂的界面,虽然看起来和前一个界面基本上一样,但是内部的代码完全不同,此处重点解释内部的代码:
xml version="1.0"encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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"
tools:context="com.dzjin.drawer.myapplication.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>
<includelayout="@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"
app:srcCompat="@android:drawable/ic_dialog_email"/>
android.support.design.widget.CoordinatorLayout>
通过这个布局,我们把标题栏和内容面板以及悬浮按钮集合在一起,但是主界面中除了这些还应该有侧滑栏,那么下一个布局文件我们就将上一个布局和侧滑栏整合在一起,构成主界。
这是最后整合前面所有布局的布局,首先来看一下实现的效果:
是不是感觉很复杂又很有成就感啊,下面我们来一一说明这个布局:
xml version="1.0"encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://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>
packagecom.dzjin.drawer.myapplication;
importandroid.os.Bundle;
importandroid.support.design.widget.FloatingActionButton;
importandroid.support.design.widget.Snackbar;
importandroid.view.View;
importandroid.support.design.widget.NavigationView;
importandroid.support.v4.view.GravityCompat;
importandroid.support.v4.widget.DrawerLayout;
importandroid.support.v7.app.ActionBarDrawerToggle;
importandroid.support.v7.app.AppCompatActivity;
importandroid.support.v7.widget.Toolbar;
importandroid.view.MenuItem;
/**
* 这个Activity要实现一个接口,用于响应菜单的单击事件,做出处理
*/
public classMainActivityextendsAppCompatActivity
implementsNavigationView.OnNavigationItemSelectedListener {
@Override
protected voidonCreate(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(newView.OnClickListener() {
@Override
public voidonClick(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 是 DrawerLayout.DrawerListener实现,和 NavigationDrawer搭配使用,推荐用这个方法,符合Android design规范。
ActionBarDrawerToggle toggle =new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
//获取导航视图并设置菜单监听,对应上面实现的接口
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public voidonBackPressed() {//当按下返回键的时候,对抽屉进行设置,这个地方要知道如何关闭和打开抽屉
/**
* drawer.closeDrawer(GravityCompat.START);从开始关闭抽屉
* drawer.openDrawer();打开抽屉,方向自选
*/
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if(drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public booleanonNavigationItemSelected(MenuItem item) {//当导时航栏菜单被单击时,根据ID判断并给出响应
// Handle navigation view item clicks here.
intid = 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;
}
}
至此,侧滑已经完全实现,下面我们考虑一个问题,如果我们要点击导航的头部中的ImageView,并进行响应,比如说更换头像,沃恩应该怎么进行获得ImageView并对其设置监听呢?按照之前对悬浮按钮的设置方式,对ImageView做如下设置:
ImageView imageView=(ImageView)findViewById(R.id.imageView);
imageView.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View view) {
}
});
但是,非常不幸的出现了以下一幕:
查看输出:
java.lang.RuntimeException:Unabletostartactivity ComponentInfo{com.dzjin.drawer.myapplication/com.dzjin.drawer.myapplication.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
空指针异常。。。。。。可是悬浮窗明明用的好好的,这个ImageView就不行了呢?下面我们来一起探讨一下这个问题。
我们先来看一下这句话:
ImageView imageView=(ImageView)findViewById(R.id.imageView);
这句话就是获得ImageView,find之前默认有一个this,view.find.....,那么这个View就是我们刚才设置的ContentView,很明显,这句话没能返回一个ImageView。
我们在去看activity_main.xml布局文件,可以看到悬浮窗是被include进来的,可以直接获得,于是我们就需要考虑NavLayout中HeaderLayout内部控件的事件处理。基本的处理过程如下。
通过navView获得LinearLayout,并通过LinearLayout获得ImageView,OK。
LinearLayout linearLayout=(LinearLayout) navigationView.inflateHeaderView(R.layout.nav_header_main);
ImageView imageView=(ImageView)linearLayout.findViewById(R.id.imageView);
imageView.setOnClickListener(newView.OnClickListener() {
@Override
public voidonClick(View view) {
}
});
但是出现了奇葩的一幕:
出现了两个头部,主要是因为我么分别的xml和java中加载了一次,我们可以选择去掉app:headerLayout="@layout/nav_header_main" 或者在java中使用View headerView = navigationView.getHeaderView(0); OK