1,不多废话,直接来效果图如下:
拓展
如上图我们可以看出图一和QQ侧滑菜单基本一样。图二进行了水平和竖直方向上的缩放。
2,DrawerLayout来实现这些效果
首先我相信很多人都用过v4包里面的DrawerLayout吧,其实使用起来很点单,我们通过源码发现,DrawerLayout继承ViewGroup作为容器,我们只需要在它内部设置两个容器布局作为内容页面和侧滑页面就可以搞定。同时设置android:layout_gravity属性就可以实现简单的侧滑效果:代码如下activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawable_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--这个是中间的内容布局:android:layout_gravity不写或者为centry那么为中间布局-->
<LinearLayout
android:background="@drawable/neirou"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
<!--这个是左边点侧滑菜单布局:android:layout_gravity设置为left或者start就会默认为侧滑菜单布局-->
<LinearLayout
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@drawable/rightss"
android:orientation="vertical">
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
就这样其他的东西不用设置。我们运行之后如下图所示:
但是我们会发现,当侧滑菜单出现的时候中间的内容布局并没有动而是被侧滑布局覆盖。这样交互性不太好
吧。我们如何来实现侧滑布局出现之后,中间内容布局也向右边滑动呢?
这时候我们关联DrawerLayout看看源码他的侧滑是如何实现的。我们能不能根据源码来得到消息呢?
我们确定目前我们就在xml中设置了侧滑菜单和中间内容布局,就可以实现滑动,我们并没有进行代码设置,所
以我们从它的构造方法去看,到底侧滑如何实现的。源码发现如下:
public DrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
final float density = getResources().getDisplayMetrics().density;
mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);
final float minVel = MIN_FLING_VELOCITY * density;
mLeftCallback = new ViewDragCallback(Gravity.LEFT);
mRightCallback = new ViewDragCallback(Gravity.RIGHT);
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);
// So that we can catch the back button
setFocusableInTouchMode(true);
ViewCompat.setImportantForAccessibility(this,
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
ViewGroupCompat.setMotionEventSplittingEnabled(this, false);
if (ViewCompat.getFitsSystemWindows(this)) {
IMPL.configureApplyInsets(this);
mStatusBarBackground = IMPL.getDefaultStatusBarBackground(context);
}
mDrawerElevation = DRAWER_ELEVATION * density;
mNonDrawerViews = new ArrayList<View>();
}
我们可以发现默认构造方法里面有ViewDragHelper有侧滑帮助类以及回调接口
ViewDragCallback我们继续查看可以发现好多的测量和事件解决,从而我们
默认的xml就可以实现侧滑效果。那么我们如何自己在原来的基础上进行拓展来设置
出自己多样的侧滑效果呢?我们继续在源码面看有没有抽屉容器框架的监听方法,
而且里面有我们滑动所需要的参数。我们会发现:
/**
* Set a listener to be notified of drawer events. Note that this method is deprecated
* and you should use {@link #addDrawerListener(DrawerListener)} to add a listener and
* {@link #removeDrawerListener(DrawerListener)} to remove a registered listener.
*
* @param listener Listener to notify when drawer events occur
* @see DrawerListener
* @see #addDrawerListener(DrawerListener)
* @see #removeDrawerListener(DrawerListener)
*/
@Deprecated
public void setDrawerListener(DrawerListener listener) {
// The logic in this method emulates what we had before support for multiple
// registered listeners.
if (mListener != null) {
removeDrawerListener(mListener);
}
if (listener != null) {
addDrawerListener(listener);
}
// Update the deprecated field so that we can remove the passed listener the next
// time we're called
mListener = listener;
}
/**
* Adds the specified listener to the list of listeners that will be notified of drawer events.
*
* @param listener Listener to notify when drawer events occur.
* @see #removeDrawerListener(DrawerListener)
*/
public void addDrawerListener(@NonNull DrawerListener listener) {
if (listener == null) {
return;
}
if (mListeners == null) {
mListeners = new ArrayList<DrawerListener>();
}
mListeners.add(listener);
}
我们发现开发这提供了setDrawerListener和addDrawerListener方法,谷歌工程
师它们本身不推荐setDrawerListner方法,而是使用addDrawerListener方法,而
且需要在activity销毁时候将监听事件移除。可能是为了释放闲置时候的实例,减轻内
存吧。接下来我们通过addDrawerListener来进行得到我们所需要的效果。
3,代码部分
1)我们首先定义一个内部类MyDrawerListener进行实现这个接口代码如下这样我们可以随时销毁和利用:
class MyDrawerListener implements DrawerLayout.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) {
}
}
我们通过源码可知道onDrawerSlide(View drawerView, float slideOffset)
方法可以进行侧滑菜单布局和内容布局滑动时候的动作和行为改变。drawerView是代表侧滑菜单布局android:layout_gravity设置为left或者start或者right。slideOffset是左边或者右边菜单布局拖拽滑动从无到有变化slideOffset从0-1代表左边布局滑动出的所占比例:如下图分析
2)我们来实现qq的那种效果:我们观察其实qq就是左边滑动之后中间的布局也向右边滑动而已。
我们以及知道了左边布局向右边滑动的slideOffset是0-1:我们可以计算出中间布局滑动的距离和左边的一样就可以代码如下:
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
//实例化中间布局
View zhong_view = drawerLayout.findViewById(R.id.neirou);
//左边的布局,用来后去移动的距离,从而设置中间布局移动距离动画大小
View rightview = drawerView;
//通过左边移动的距离设置中间的距离
zhong_view.setTranslationX(rightview.getMeasuredWidth() *slideOffset);//0-width;
}
运行效果如下:
3)我们来根据slideOffset来设置让侧滑菜单又小变大。中间的布局x和y轴安比例缩小:我们看图分析
我打算将左边侧滑菜单X和Y轴从0.8到1,中间的布局X和Y轴从1到0.8。首先我们知道slideOffset是从
0-1那么我们就可以设置左边布局X和Y变动比例为leftScaleXY=1-(1-slideOffset)*0.2范围为:0.8-1。中
间的布局距离变化为1-0.8:centerScaleXY=1-slideOffset*0.2范围:1-0.8。这里我们确定2个布局 X和Y缩放范围我直接贴出代码了:
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
//中间的布局
View zhong_view = drawerLayout.findViewById(R.id.neirou);
//左边侧滑的布局
View rightview = drawerView;
float leftScaleXY = (float) (1 - (1 - slideOffset) * 0.2);
float centerScaleXY= (float) (1-slideOffset*0.2);
//让左边的布局X和Y轴由0.8-1:
rightview.setScaleX(leftScaleXY);
rightview.setScaleY(leftScaleXY);
//中间的布局X和Y轴由1-0.8:
zhong_view.setScaleX(centerScaleXY);
zhong_view.setScaleY(centerScaleXY);
zhong_view.setTranslationX(rightview.getMeasuredWidth() * slideOffset);//0-width;
}
在Activiy中设置:
drawerLayout.addDrawerListener(drawerableLinstner);
在onPause里面移除这个监听类:
@Override
protected void onPause() {
super.onPause();
if(drawerableLinstner!=null) {
drawerLayout.removeDrawerListener(drawerableLinstner);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(drawerableLinstner!=null) {
drawerLayout.removeDrawerListener(drawerableLinstner);
}
}
这时候我们运行结果如下:
项目地址github: https://github.com/luhenchang/Lsn7_MaterialDesign_SlidingMenu_drawerLayout.git