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

网上很多菜单框架,但应用最多,最经典的应该还是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的图片,所有图片来自鸿洋大神的 博客中,鸿洋大神也曾讲过类似的实现,从中也学到不少东西)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值