您的位置:首页 > 其它

SlidingMenu源码解析及简单应用案例

2015-11-16 11:43 429 查看
网上很多菜单框架,但应用最多,最经典的应该还是SlidingMenu,工作项目中也一直在用,所以决定研究一下;刚开始学习写博客,主要用于自己知识整理,及对问题解决的记录积累,请大神们多指点;很多内容也是参考很多好的博客总结的。

1.功能介绍

SlidingMenu是一个强大的侧滑菜单导航框架,已经被很多大牛App使用,主要特点:

(1)侧边栏是一个Fragment,可包含任何View

(2)使用简单,支持左右滑动,及很多监听效果等

(3)可自定义侧边栏显示动画

(4)可一根据自己需求改变样式(仿QQ5.0侧滑效果也没有问题。最后我会给出实现方法,只需简单的几行代码)

2.总体设计

总体主要又三个类组成。

(1)SlidingMenu继承自RelativeLayout,对外暴露API给用户,同时再添加CustomViewAbove和CustomViewBehind

(2)CustomViewAbove继承自ViewGroup,主要用来处理触摸屏事件

(3)CustomViewBehind继承自ViewGroup,主要用来配置参数,显示侧边栏的Menu部门

3.流程图

CustomViewAbove事件处理流程图,主要处理touch事件

4.类关系图

4.1类关系图

4.2核心类功能介绍

4.2.1 SlidingMenu.java

继承自RelativeLayout,对外提供API,用于配置侧边栏的侧滑模式,触屏模式,阴影,渐变及滑动效果等。

构造器中主要初始化了mViewBehind,mViewAbove及一些属性。

主要看attachToActivity方法

public void attachToActivity(Activity activity, int slideStyle, boolean actionbarOverlay) {
...
...
ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);
// save ActionBar themes that have transparent assets
decorChild.setBackgroundResource(background);
decor.removeView(decorChild);
decor.addView(this);
setContent(decorChild);
break;
...
...
}
这里slideStyle选取SLIDING_WINDOW的case进行分析,看到主要是获取decorView,将decorView下面的decorChild(我们的根布局)移除,把SlidingMenu添加进来,把decorChild赋值给mViewAbove。(SLIDING_CONTENT的原理差不多)

SlidingMenu常用属性设置:

// 设置侧边, 必须为 LEFT(左边),RIGHT(右边),LEFT_RIGHT(左右两边)三者之一

public void setMode(int mode)

// 设置触摸方式,必须为 TOUCHMODE_FULLSCREEN(全屏可触摸),TOUCHMODE_MARGIN(边缘可触摸),默认 48dp, TOUCHMODE_NONE(不可触摸)三者之一

public void setTouchModeAbove(int i)

// 根据资源文件 ID 设置阴影部分的 width

public void setShadowWidthRes(int resId)

// 根据资源文件 ID 设置阴影部分的效果

public void setShadowDrawable(int resId)

// 根据资源文件 ID 设置第二个侧边栏阴影部分的效果

public void setSecondaryShadowDrawable(int resId)

// 根据资源文件 ID 设置主界面距离屏幕的偏移量,也就是menu划出时主页面显示的剩余宽度

public void setBehindOffsetRes(int resID)

//设置SlidingMenu菜单的宽度

menu.setBehindWidth(400);

// 设置 fade in 和 fade out 效果的值

public void setFadeDegree(float f)

// 设置滑动比例的值,范围为 0-1 之间

public void setBehindScrollScale(float f)

// 根据资源文件 ID 设置侧边栏布局

public void setMenu(int res)

// 根据 View 设置侧边栏布局

public void setMenu(View v)

// 根据资源文件 ID 设置第二个侧边栏布局

public void setSecondaryMenu(int res)

// 根据 View 设置第二个侧边栏布局

public void setSecondaryMenu(View v)

// 打开菜单

public void showMenu()

// 打开第二个菜单

public void showSecondaryMenu()

// SlidingMenu 的开关

public void toggle()

// 检查侧边栏是否打开

public boolean isMenuShowing()

// 检查第二个侧边栏是否打开

public boolean isSecondaryMenuShowing()

//监听slidingmenu打开

menu.setOnOpenListener(onOpenListener);

关于关闭menu有两个监听,简单的来说,对于menu close事件,一个是when,一个是after

//监听slidingmenu关闭时事件

menu.OnCloseListener(OnClosedListener);

//监听slidingmenu关闭后事件

menu.OnClosedListener(OnClosedListener);

4.2.2CustomViewBehind.java
主要属性

/** 第一个侧边栏,一般为左边栏 */
private View mContent;
/** 第二个侧边栏,一般为右边栏 */
private View mSecondaryContent;
/** 滑动侧边栏的最大临界值在设置 TOUCHMODE_MARGIN 起作用,默认 48dp */
private int mMarginThreshold;
/** 侧边栏被滑出后,主界面留在屏幕上的 offset */
private int mWidthOffset;
/** 有三个值可以选,LEFT/RIGHT/LEFT_RIGHT */
private int mMode;
/** 侧边栏在侧滑过程中是否需要 fade 动画效果 */
private boolean mFadeEnabled;
/** 定义滑动比例的值,范围 0-1f */
private float mScrollScale;
/** 侧边栏滑出后的阴影部分,demo 中用的是 Gradient */
private Drawable mShadowDrawable;
/** 同上,为第二个侧边栏的阴影部分 */
private Drawable mSecondaryShadowDrawable;
/** 阴影部分的宽 */
private int mShadowWidth;
/** 侧边栏滑动过程中 fade 动画的值,范围 0-1f */
private float mFadeDegree;
在侧边栏滑动过程中, 通过回调 CustomViewAbove 的 dispatchDraw 方法画阴影部分和 fade in/out 效果。

// 画阴影部分

public void drawShadow(View content, Canvas canvas)

// 根据 openPercent 画 fade in/out 效果

public void drawFade(View content, Canvas canvas, float openPercent)

最后,实现下面这样QQ5.0效果的侧滑,其实很简单只需要几行代码

(是我工作中代码片段,主要实现的代码就是红色部分)

// 实例化滑动菜单对象
SlidingMenu sm = getSlidingMenu();
// 设置可以左右滑动的菜单
sm.setMode(SlidingMenu.LEFT);
sm.setBehindWidthRes(R.dimen.left_menu_width);
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);
sm.setFadeDegree(0.25f);
sm.setBehindScrollScale(0.25f);
sm.setFadeEnabled(false);

sm.setBackgroundImage(R.drawable.bg_menu_top);
<span style="color:#FF0000;"> sm.setBehindCanvasTransformer(new SlidingMenu.CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
float scale = (float) (percentOpen * 0.25 + 0.75);
canvas.scale(scale, scale, -canvas.getWidth() / 2,
canvas.getHeight() / 2);
}
});

sm.setAboveCanvasTransformer(new SlidingMenu.CanvasTransformer() {
@Override
public void transformCanvas(Canvas canvas, float percentOpen) {
float scale = (float) (1 - percentOpen * 0.25);
canvas.scale(scale, scale, 0, canvas.getHeight() / 2);
}
});</span>

sm.setOnCloseListener(new SlidingMenu.OnCloseListener() {
@Override
public void onClose() {
isPopTitleOpen = false;
iv_alpha.setVisibility(View.INVISIBLE);
if (mRlPopTitle != null && pageIndex == 0) {
mRlPopTitle.setVisibility(View.VISIBLE);
} else {
mRlPopTitle.setVisibility(View.INVISIBLE);
}
}
});
sm.setOnOpenedListener(new SlidingMenu.OnOpenedListener() {
@Override
public void onOpened() {
isPopTitleOpen = true;
if (mRlPopTitle != null) {
mRlPopTitle.setVisibility(View.INVISIBLE);
}
}
});
sm.setOnOpenListener(new SlidingMenu.OnOpenListener() {
@Override
public void onOpen() {
isPopTitleOpen = true;
if (mRlPopTitle != null) {
mRlPopTitle.setVisibility(View.INVISIBLE);
}
}
});
setBehindContentView(R.layout.menu_frame_left);
实现思路:主要就是给AboveView的尺寸重试画一个尺寸。

效果图:(由于不会弄gift的图片,所有图片来自鸿洋大神的 博客中,鸿洋大神也曾讲过类似的实现,从中也学到不少东西)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: