SwipeMenuListView框架完全解析,swipemenulistview
SwipeMenuListView(滑动菜单)
A swipe menu for ListView.--一个非常好的滑动菜单开源项目。
Demo

一、简介
看了挺长时间的自定义View和事件分发,想找一个项目练习下。。正好印证自己所学。
在github上找到了这个项目:SwipeMenuListView这的真不错,对事件分发和自定义View都很有启发性,虽然还有点小瑕疵,后面说明。想了解滑动菜单怎么实现的同学,这篇文章绝对对你有帮助,从宏观微观角度详细分析了每个文件。
项目地址:https://github.com/baoyongzhang/SwipeMenuListView/tree/b00e0fe8c2b8d6f08607bfe2ab390c7cee8df274 版本:b00e0fe 它的使用很简单只需要三步,在github上就可以看懂就不占用篇幅啦,本文只分析原理。另外如果你看代码感觉和我不一样,看着困难的话,可以看我加了注释的:http://download.csdn.net/detail/jycboy/9667699
先看两个图:有一个大体的了解
这是框架中所有的类。
1.下面的图是视图层次:

上面的图中:SwipeMenuLayout是ListView中item的布局,分左右两部分,一部分是正常显示的contentView,一部分是滑出来的menuView;滑出来的SwipeMenuView继承自LinearLayout,添加view时,就是横向添加,可以横向添加多个。
2.下面的图是类图结构:

上面是类之间的调用关系,类旁边注明了类的主要作用。
二、源码分析
SwipeMenu?、SwipeMenuItem是实体类,定义了属性和setter、getter方法,看下就行。基本上源码的注释很清楚。
2.1 SwipeMenuView?: 代码中注释的很清楚
/**
* 横向的LinearLayout,就是整个swipemenu的父布局
* 主要定义了添加Item的方法及Item的属性设置
* @author baoyz
* @date 2014-8-23
*
*/
public class SwipeMenuView extends LinearLayout implements OnClickListener {
private SwipeMenuListView mListView;
private SwipeMenuLayout mLayout;
private SwipeMenu mMenu;
private OnSwipeItemClickListener onItemClickListener;
private int position;
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public SwipeMenuView(SwipeMenu menu, SwipeMenuListView listView) {
super(menu.getContext());
mListView = listView;
mMenu = menu; //
// MenuItem的list集合
List<SwipeMenuItem> items = menu.getMenuItems();
int id = 0;
//通过item构造出View添加到SwipeMenuView中
for (SwipeMenuItem item : items) {
addItem(item, id++);
}
}
/**
* 将 MenuItem 转换成 UI控件,一个item就相当于一个垂直的LinearLayout,
* SwipeMenuView就是横向的LinearLayout,
*/
private void addItem(SwipeMenuItem item, int id) {
//布局参数
LayoutParams params = new LayoutParams(item.getWidth(),
LayoutParams.MATCH_PARENT);
LinearLayout parent = new LinearLayout(getContext());
//设置menuitem的id,用于后边的点击事件区分item用的
parent.setId(id);
parent.setGravity(Gravity.CENTER);
parent.setOrientation(LinearLayout.VERTICAL);
parent.setLayoutParams(params);
parent.setBackgroundDrawable(item.getBackground());
//设置监听器
parent.setOnClickListener(this);
addView(parent); //加入到SwipeMenuView中,横向的
if (item.getIcon() != null) {
parent.addView(createIcon(item));
}
if (!TextUtils.isEmpty(item.getTitle())) {
parent.addView(createTitle(item));
}
}
//创建img
private ImageView createIcon(SwipeMenuItem item) {
ImageView iv = new ImageView(getContext());
iv.setImageDrawable(item.getIcon());
return iv;
}
/*根据参数创建title
*/
private TextView createTitle(SwipeMenuItem item) {
TextView tv = new TextView(getContext());
tv.setText(item.getTitle());
tv.setGravity(Gravity.CENTER);
tv.setTextSize(item.getTitleSize());
tv.setTextColor(item.getTitleColor());
return tv;
}
@Override
/**
* 用传来的mLayout判断是否打开
* 调用onItemClick点击事件
*/
public void onClick(View v) {
if (onItemClickListener != null && mLayout.isOpen()) {
onItemClickListener.onItemClick(this, mMenu, v.getId());
}
}
public OnSwipeItemClickListener getOnSwipeItemClickListener() {
return onItemClickListener;
}
/**
* 设置item的点击事件
* @param onItemClickListener
*/
public void setOnSwipeItemClickListener(OnSwipeItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public void setLayout(SwipeMenuLayout mLayout) {
this.mLayout = mLayout;
}
/**
* 点击事件的回调接口
*/
public static interface OnSwipeItemClickListener {
/**
* onClick点击事件中调用onItemClick
* @param view 父布局
* @param menu menu实体类
* @param index menuItem的id
*/
void onItemClick(SwipeMenuView view, SwipeMenu menu, int index);
}
}
**SwipeMenuView?就是滑动时显示的View,看他的构造函数SwipeMenuView(SwipeMenu menu, SwipeMenuListView listView)?;遍历Items:menu.getMenuItems();调用addItem方法向?SwipeMenuView中添加item。
在addItem方法中:每一个item都是一个LinearLayout?。
2.2 SwipeMenuLayout?:
这个类代码有点长,我们分成三部分看,只粘贴核心代码,剩下的看一下应该就懂啦。
public class SwipeMenuLayout extends FrameLayout {
private static final int CONTENT_VIEW_ID = 1;
private static final int MENU_VIEW_ID = 2;
private static final int STATE_CLOSE = 0;
private static final int STATE_OPEN = 1;
//方向
private int mSwipeDirection;
private View mContentView;
private SwipeMenuView mMenuView;
。。。。。
public SwipeMenuLayout(View contentView, SwipeMenuView menuView) {
this(contentView, menuView, null, null);
}
public SwipeMenuLayout(View contentView, SwipeMenuView menuView,
Interpolator closeInterpolator, Interpolator openInterpolator) {
super(contentView.getContext());
mCloseInterpolator = closeInterpolator;
mOpenInterpolator = openInterpolator;
mContentView = contentView;
mMenuView = menuView;
//将SwipeMenuLayout设置给SwipeMenuView,用于判断是否打开
mMenuView.setLayout(this);
init();
}
private void init() {
setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
mGestureListener = new SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
isFling = false;
return true;
}
@Override
//velocityX这个参数是x轴方向的速率,向左是负的,向右是正的
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
// TODO
if (Math.abs(e1.getX() - e2.getX()) > MIN_FLING
&& velocityX < MAX_VELOCITYX) {
isFling = true;
}
Log.i("tag","isFling="+isFling+" e1.getX()="+e1.getX()+" e2.getX()="+e2.getX()+
" velocityX="+velocityX+" MAX_VELOCITYX="+MAX_VELOCITYX);
// Log.i("byz", MAX_VELOCITYX + ", velocityX = " + velocityX);
return super.onFling(e1, e2, velocityX, velocityY);
}
};
mGestureDetector = new GestureDetectorCompat(getContext(),
mGestureListener);
。。。。
LayoutParams contentParams = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
mContentView.setLayoutParams(contentParams);
if (mContentView.getId() < 1) {
//noinspection ResourceType
mContentView.setId(CONTENT_VIEW_ID);
}
//noinspection ResourceType
mMenuView.setId(MENU_VIEW_ID);
mMenuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
addView(mContentView);
addView(mMenuView);
}
从上边的init方法中可以看出SwipeMenuLayout由两部分组成,分别是用户的 item View 和 menu View 。手

