您的位置:首页 > 移动开发 > Android开发

DrawerLayout和NavigationView轻松实现抽屉侧滑

2017-07-17 10:25 351 查看
在android5.0后谷歌添加了DrawerLayout和NavigationView两个控件,使用这两个控件可以很轻松的实现抽屉侧滑效果,这里说先DrawerLayout;

DrawerLayout:

DrawerLayout是MateriaDesign风格中的控件,来自support-v4包里面,相当于一个自定义容器 extends ViewGroup ,可以看作是一个有侧滑效果的帧布局。

1、DrawerLayout+ToolBar实现抽屉侧滑

在使用DrawerLayout的时候要将DrawerLayout作为内容布局和侧滑菜单布局的父布,

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary">
</android.support.v7.widget.Toolbar>
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.drawerlayoutdemo.MainActivity">
<!--内容部分-->
<ListView
android:id="@+id/content_list"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
<!--侧滑菜单部分左边-->
<ListView
android:id="@+id/left"
android:layout_width="150dp"
android:layout_gravity="start"
android:layout_height="match_parent"
android:background="@android:color/white">

</ListView>
<!--侧滑菜单部分右边-->
<ListView
android:id="@+id/right"
android:layout_width="match_parent"
android:layout_marginLeft="50dp"
android:layout_gravity="end"
android:layout_height="match_parent"
android:background="@android:color/white">
</ListView>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>


在侧滑菜单布局中要添加android:layout_gravity=”end”,这样DrawerLayout才会辨别哪个是侧滑菜单,这里提供了是个属性值;

@IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})


LEFT和START表示左边侧滑,RIGHT和END表示右边侧滑,GravityCompat.START和GravityCompat.END是为了兼容低版本,布局文件写好后,将布局文件中的控件引入进来;

drawerLayout= (DrawerLayout) findViewById(R.id.drawer_layout);
toolbar= (Toolbar) findViewById(R.id.toolbar);
//设置Toolbar
setSupportActionBar(toolbar);
//将DrawerLayout和Toolbar关联
ActionBarDrawerToggle toggle=new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.drawer_open,R.string.drawer_close);
//进行同步
toggle.syncState();
//添加事件监听
drawerLayout.addDrawerListener(toggle);


没错就这些代码就已经实现了一个抽屉侧滑效果;



实现了左右侧滑,点击ToolBar左边可以打开或关闭侧滑菜单,点击条目同样可以响应点击事件;

DrawerLayout单独使用实现抽屉侧滑

如果不想结合ToolBar来实现侧滑效果也是可以的,下面这个就是DrawerLayout单独使用实现抽屉侧滑,布局文件还是一样的没有变化,只是将标题栏改成了RelativeLayout,RelativeLayout里面放了一个imageview,点击imageview或者ListView条目来控制DrawerLayout打开或关闭;

iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
index++;
if (index % 2 == 0) {
//打开
drawerLayout.openDrawer(GravityCompat.START, true);
} else {
//关闭
drawerLayout.closeDrawer(GravityCompat.START, true);
}
}
});


调用DrawerLayout里面的openDrawer或者closeDrawer就可以设置打开还是关闭,不过在设置的时候要注意,GravityCompat.START要和布局文件中的android:layout_gravity=”start”要相对应,这样就可以了;



注:点击条目打开右边侧滑菜单的效果有点类似于易车网App选车列表效果

如果只是想点击的时候打开侧滑菜单,左右滑动的时候不打开也是可以的,调用setDrawerLockMode();就可以设置打开还是关闭;lockMode参数有四个选择:

/**
* The drawer is unlocked.
*/
public static final int LOCK_MODE_UNLOCKED = 0;

/**
* The drawer is locked closed. The user may not open it, though
* the app may open it programmatically.
*/
public static final int LOCK_MODE_LOCKED_CLOSED = 1;

/**
* The drawer is locked open. The user may not close it, though the app
* may close it programmatically.
*/
public static final int LOCK_MODE_LOCKED_OPEN = 2;

/**
* The drawer's lock state is reset to default.
*/
public static final int LOCK_MODE_UNDEFINED = 3;


//设置左边和右边关闭或者打开
public void setDrawerLockMode(@LockMode int lockMode) {
setDrawerLockMode(lockMode, Gravity.LEFT);
setDrawerLockMode(lockMode, Gravity.RIGHT);
}


//设置左边或者右边打开或者关闭  edgeGravity可以是Gravity.LEFT, //Gravity.RIGHT, GravityCompat.START, GravityCompat.END里
//面的任意一个
public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) {
...
}


//指定对应的View侧滑打开或者关闭
public void setDrawerLockMode(@LockMode int lockMode, View drawerView) {
...
setDrawerLockMode(lockMode, gravity);
}


第一个和第三个最终还是调用的是第二个;接下来就去看看DrawerLayout的源码;

DrawerLayout源码:

public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
...
mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);
mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
mLeftDragger.setMinVelocity(minVel);
mLeftCallback.setDragger(mLeftDragger);

mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback);
mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
mRightDragger.setMinVelocity(minVel);
mRightCallback.setDragger(mRightDragger);
...
}


在DrawerLayout构造方法里面可以看到DrawerLayout是利用ViewDragHelper这里类来实现侧滑效果的;在DrawerLayout和ToolBar结合使用的时候还涉及到了ActionBarDrawerToggle类,

ActionBarDrawerToggle类提供了两个构造方法;

public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout,
@StringRes int openDrawerContentDescRes,
@StringRes int closeDrawerContentDescRes) {
this(activity, null, drawerLayout, null, openDrawerContentDescRes,
closeDrawerContentDescRes);
}


public ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout,
Toolbar toolbar, @StringRes int openDrawerContentDescRes,
@StringRes int closeDrawerContentDescRes) {
this(activity, toolbar, drawerLayout, null, openDrawerContentDescRes,
closeDrawerContentDescRes);
}


调用syncState();方法后就将ToolBar和DrawerLayout同步,

public void syncState() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
setPosition(1);
} else {
setPosition(0);
}
...
}


private void setPosition(float position) {
if (position == 1f) {
mSlider.setVerticalMirror(true);
} else if (position == 0f) {
mSlider.setVerticalMirror(false);
}
mSlider.setProgress(position);
}


走到这里涉及到DrawerArrowDrawable类,DrawerArrowDrawable extend Drawable,根据传进来的position调用DrawerArrowDrawable 中的setProgress();方法进行绘制;

public void setProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
if (mProgress != progress) {
mProgress = progress;
//进行绘制,最终调用父类中的方法进行绘制drawable
invalidateSelf();
}
}


Drawable类中的invalidateSelf();方法

public void invalidateSelf() {
final Callback callback = getCallback();
if (callback != null) {
callback.invalidateDrawable(this);
}
}


这样就会在侧滑菜单打开或关闭的时候,对三道杠或者箭头进行切换绘制;如果想在打开或关闭的时候进行监听添加其他效果可以调用DrawerLayout中的setDrawerListener或者addDrawerListener,不过建议调用addDrawerListener,setDrawerListener已经过时了,

@Deprecated
public void setDrawerListener(DrawerListener listener) {
//如果之前的DrawerListener还存在就将其移除调
if (mListener != null) {
removeDrawerListener(mListener);
}
//添加新的DrawerListener
if (listener != null) {
addDrawerListener(listener);
}
//将新的DrawerListener赋值给之前的DrawerListener
mListener = listener;
}
public void addDrawerListener(@NonNull DrawerListener listener) {
if (listener == null) {
return;
}
//利用集合来管理DrawerListener
if (mListeners == null) {
mListeners = new ArrayList<DrawerListener>();
}
mListeners.add(listener);
}


//给侧滑控件设置监听
drawerlayout.setDrawerListener(new DrawerListener() {

@Override
public void onDrawerStateChanged(int newState) {
// 状态发生改变

}

@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// 滑动的过程当中不断地回调 slideOffset:0~1

}

@Override
public void onDrawerOpened(View drawerView) {
// 打开

}

@Override
public void onDrawerClosed(View drawerView) {
// 关闭

}
});


如果不想实现全部方法的话可以使用SimpleDrawerListener,SimpleDrawerListener implements DrawerListener;

public abstract static class SimpleDrawerListener implements DrawerListener {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
}

@Override
public void onDrawerOpened(View drawerView) {
}

@Override
public void onDrawerClosed(View drawerView) {
}

@Override
public void onDrawerStateChanged(int newState) {
}
}


这样可以根据自己的需要进行方法的重写,其他的一些方法在使用的时候可以细看源码,总的来说DrawerLayout使用起来还是比较灵活的;

NavigationView

NavigationView也是谷歌在android5.0推出来的一个侧滑控价,目的是为了用来规范侧滑的基本样式;NavigationView使用的时候要结合DrawerLayout一起使用;

1、引入依赖库

compile 'com.android.support:design:26.0.0-alpha1'


2、在xml文件中使用

将DrawerLayout作为内容布局和侧滑菜单布局的父布局,使用NavigationView作为侧滑菜单;

<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 内容部分 -->
<FrameLayout
android:id="@+id/fl"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<!-- 菜单部分 -->
<android.support.design.widget.NavigationView
android:layout_gravity="start"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
app:menu="@menu/navigation_menu"
app:headerLayout="@layout/navigation_headerlayout"
/>
</android.support.v4.widget.DrawerLayout>


app:menu  侧滑菜单的条目
app:headerLayout  侧滑菜单条目上面的头部布局


这样效果就实现了,是不是比DrawerLayout还要简单;



但是NavigationView是为了规范侧滑的基本样式的,侧滑菜单的样式就不好改变,条目就只能采用menu的方式实现,使用起来就没有DrawerLayout那么灵活,在开发中,效果不是很炫的话,可以使用DrawerLayout来实现,当前自定义的话也可以。

源码地址:

http://download.csdn.net/detail/wangwo1991/9909251
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息