Skip to content

Latest commit

 

History

History

side-menu.android

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

Side Menu.Android 源码解析

本文为 Android 开源项目源码解析 中 Side Menu.Android 部分
项目地址:Side Menu.Android,分析的版本:2c23bff,Demo 地址:side-menu-demo
分析者:cpacm,校对者:lightSky,校对状态:完成

1. 功能介绍

一个交互的动画侧边菜单——Side Menu

1.1 特点

提供了一个翻页动画——Flip Animation

1.2 要求

**(1)**主界面布局需要使用 DrawerLayout 作为容器
**(2)**内容界面需要继承 ScreenShotable 接口(如 demo 中的 ContentFragment),以便为 Reveal 效果提供 Bitmap 资源。
**(4)**主界面需要实现 ViewAnimator.ViewAnimatorListener 接口(如 demo 中的 myActivity)。

2. 流程图

流程图

3. 详细设计

3.1 核心类介绍

3.1.1 ViewAnimator SideMenu 的管理类

其构造函数需要传入 5 个参数,分别为作为主界面的 ActionBarActivity子按钮列表实现 ScreenShotable 接口的信息界面DrawerLayout实现 ViewAnimatorListener 接口的主界面

public ViewAnimator(ActionBarActivity activity,
                        List<T> items,
                        ScreenShotable screenShotable,
                        final DrawerLayout drawerLayout,
                        ViewAnimatorListener animatorListener) {
        this.actionBarActivity = activity;
        this.list = items;
        this.screenShotable = screenShotable;
        this.drawerLayout = drawerLayout;
        this.animatorListener = animatorListener;
    }

showMenuContent()
打开菜单界面,简单地将其分成几部分:
(1)在菜单未完全打开前设置按钮为不可用,同时调用 ViewAnimatorListener 接口中的 disableHomeButton() 方法清空原先存放按钮视图的列表。

(2)根据传入的按钮个数生成相应个数的按钮 View,并为每个按钮添加点击事件,当事件发生时回调 onSwitch 方法并关闭菜单列表。

(3)将其添加到存放按钮视图的列表中。调用 AnimatorListener 接口的addViewToContainer(viewMenu)方法(我们要在 Activity 中人为的将其添加到界面布局中)。在菜单打开动画未完成情况下,将其属性设为不可用。调用animateView()方法使用 FlipAnimation 类来实现动画设置,Handler 实现延时播放。

onSwitch

/**
 *参数分别为:选中的按钮,当前的信息界面,触摸点的 Y 坐标
 **/
animatorListener.onSwitch(slideMenuItem, screenShotable, topPosition)

当点击 MenuItem 切换 ContentView 的时候,调用 onSwitch,从指定的 ScreenShotable 实现类身上获取通过 takeScreenShot 得到的 Bitmap,然后交给 CircularReveal 确定 Reveal 效果的位图以及触发点的 position,紧接着启动 Reveal 动画,最后切换底部内容界面 ContentView,这里的 ContentView 为 Fragment

hideMenuContent()
关闭菜单界面,为每个按钮视图调用animateHideView()方法来设置关闭的动画,并通过 Handler 进行延时播放。在动画结束的监听器中设置视图不可见,并但视图是最后一个按钮时调用

animatorListener.enableHomeButton();//回调函数,使主界面的菜单键生效
drawerLayout.closeDrawers();

ViewAnimatorListener
主界面需要实现的接口,用于管理控制器的状态,向 MenuLayout 中添加 MenuItem,以及菜单切换动作的回调处理。

disableHomeButtonenableHomeButton
在主界面中处理 SideMenu 的状态时使用。你的菜单控制器可以是任意的 View,只需要实现这两个接口去处理控制器的状态即可。

addViewToContainer
向开发者的 MenuLayout 上添加 MenuItem

onSwitch
点击菜单切换视图时的回调。主要用于实现切换效果的实现,这里实现的是Reveal效果,使用了第三方的开源库:CircularReveal,而该 Reveal 效果库需要一个 Bitmap,以及 Reveal 的触发点。

 public interface ViewAnimatorListener {

        public ScreenShotable onSwitch(Resourceble slideMenuItem, ScreenShotable screenShotable, int position);

        public void disableHomeButton();

        public void enableHomeButton();

        public void addViewToContainer(View view);

    }

3.1.2 SlideMenuItem 选项按钮类

一个按钮容器类,里面存放着两个变量,主要用来设置菜单按钮。

    private String name;//名称
    private int imageRes;//图片 id

3.1.3 FlipAnimation 翻转动画

一个翻转动画工具类,继承自 Animation 类。根据传入的参数来实现不同的翻转效果。

 /**
  * 参数分别为:起始角度,终止角度,中心点的 X 坐标,中心点的 Y 坐标
  **/
 public FlipAnimation(float fromDegrees, float toDegrees,float centerX, float centerY) {
 ...
 }

3.1.4 Resourceble 选项接口

按钮选项必须继承该接口(如 SlideMenuItem 就继承了该接口),用于存放资源。

public interface Resourceble {
    public int getImageRes();
    public String getName();
}

3.1.1 ScreenShotable

用于信息变更的接口,实现切换效果,显示内容的 View 需要去实现它,该接口包含两个方法:

public interface ScreenShotable {
    public void takeScreenShot();
    public Bitmap getBitmap();
}

1、takeScreenShot()方法是在按钮被点击时触发,从方法名可以看出该方法是为了对当前界面进行快照,该快照是为了 Reaveal 效果提供 Bitmap。
2、getBitmap()方法,获取 takeScreenShot 为当前界面创建的 Bitmap,用于 Reveal 效果。

3.2 类关系图

类图

4.个人总结

一个很简单的一个项目,所以从难度上没有什么好讲的(自己的收获则是熟悉了在 Android5.0 下 Toolbar 的用法)。
我认为问题最大的是它的扩展性太差,从 ViewAnimator 类的构造函数就能发现这个库一定要在相应的环境下(ActionBarActivity,DrawerLayout)才会产生作用。
其次是动画类型不能让开发者进行二次定制,要想改变动画类型则要进 library 库进行修改。最后是 ViewAnimator 里的很多设置是通过回调函数返回给开发者自己设置,感觉变得更复杂了。
总体上而言这更像专门定制的一款 UI 设计。不过我认为它最大的意义在于提供了一种在 Toolbar 下自定义菜单的思路,这是最值得我们借鉴的~