首先声明本文是基于GitHub上"baoyongzhang"的SwipeMenuListView修改而来,
该项目地址:https://github.com/baoyongzhang/SwipeMenuListView
可以说这个侧滑删除效果是我见过效果最好且比较灵活的项目,没有之一!!!
但是在使用它之前需要给大家提两点注意事项:
1,该项目支持Gradle dependence,但是目前作者提供的依赖地址对应的项目不是最新的项目,依赖过后的代码与demo中使用的不一致,会提示没有BaseSwipeListAdapter这个类,因为这个类是其他的开发者后来提交上去的,所以如果想使用最新的代码,目前还是得把代码下载下来,然后把library文件拷贝到自己项目中使用.
下图是目前作者提供的依赖地址,不是最新的,所以想用最新代码的朋友还是直接下载代码到本地吧.
2,第二点注意事项应该算是一个bug吧,如果你测试过作者给的demo,你会发现如果某一项item已经被拉出来了,这个时候你再把ListView向上或向下滑动,让这个被拉出来的item移出屏幕,然后再移回来,这个已经被拉出来的item会直接恢复到未拉出的状态.这会让用户感觉很困惑,我明明已经拉出了这个菜单,怎么又不见了,然后可能就会产生这个软件做的真垃圾的想法,进而可能把你的软件卸载掉.如下图:
对于上面两个注意事项,第一个倒是没什么好说的,第二个问题怎么办呢?别急,这正是我们今天要说的内容.
首先我们可以先研究一下QQ的侧滑删除效果,说到这你可以打开你的qq看看它的具体效果.
你会发现,如果一个item被拉出来了,当你的手指放到其他的item上时,它会直接先把被拉出的那个item关闭掉,并且当前动作的后续的事件也都不再响应,除非你再次把手指放到屏幕上,他才会响应相关事件,而如果你的手指放到当前被拉出的item上,他不会隐藏这个item,并且可以正常响应左右滑动事件.
ok,QQ的效果我们分析完毕,我们探讨一下它的实现原理:
1,如果一个item已经被拉了出来,当你的手指放到其他的item上时,它会直接先把被拉出的那个item关闭掉, 怎么实现呢?
首先我们需要判断我们当前所按下的这个item是不是被拉出来的那个item,不是的话,我们才需要关闭,是的话,则不用管.代码如下:
if (view instanceof SwipeMenuLayout) {
SwipeMenuLayout touchView = (SwipeMenuLayout) view;
if (!touchView.isOpen()) {
mTouchView.smoothCloseMenu();
}
}
2,并且当前动作的后续的事件也都不再响应, 怎么实现呢?
这就很简单了,根据view的事件分发原理,如果在某一个触摸事件中返回了false,那么该事件后续的事件都不会再交给他处理,也就是说,如果我们在ACTION_DOWN的时候返回了false,那么后续的ACTION_MOVE,ACTION_UP等事件都不会响应,所以要实现这个效果,我们只需要在关闭菜单的后面,返回false就行了,完整的代码如下:
/********新添加的内容,当按下的item不是当前已经打开的item,则关闭已经打开的item,并返回false.不再响应down以后的事件,仿qq效果********/
if (view instanceof SwipeMenuLayout) {
SwipeMenuLayout touchView = (SwipeMenuLayout) view;
if (!touchView.isOpen()) {
mTouchView.smoothCloseMenu();
return false;
}
}
这样的几行代码就实现了刚才分析的qq效果中的前半部分效果,即如果一个item被拉出来了,当你的手指放到其他的item上时,它会直接先把被拉出的那个item关闭掉,并且当前动作的后续的事件也都不再响应,除非你再次把手指放到屏幕上,他才会响应相关事件.
上面的那几行代码是基于SwipeMenuListView类修改而来,完整的修改之后的SwipeMenuListView代码如下所示:
package com.lanma.swipemenulistviewdemo.swipemenulistview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.ListAdapter;
import android.widget.ListView;
/**
* @author baoyz
* @date 2014-8-18
* qiang_xi修改于2016-09-07(新增qq的效果)
*/
public class SwipeMenuListView extends ListView {
private static final int TOUCH_STATE_NONE = 0;
private static final int TOUCH_STATE_X = 1;
private static final int TOUCH_STATE_Y = 2;
public static final int DIRECTION_LEFT = 1;
public static final int DIRECTION_RIGHT = -1;
private int mDirection = 1;//swipe from right to left by default
private int MAX_Y = 5;
private int MAX_X = 3;
private float mDownX;
private float mDownY;
private int mTouchState;
private int mTouchPosition;
private SwipeMenuLayout mTouchView;
private OnSwipeListener mOnSwipeListener;
private SwipeMenuCreator mMenuCreator;
private OnMenuItemClickListener mOnMenuItemClickListener;
private OnMenuStateChangeListener mOnMenuStateChangeListener;
private Interpolator mCloseInterpolator;
private Interpolator mOpenInterpolator;
public SwipeMenuListView(Context context) {
super(context);
init();
}
public SwipeMenuListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public SwipeMenuListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
MAX_X = dp2px(MAX_X);
MAX_Y = dp2px(MAX_Y);
mTouchState = TOUCH_STATE_NONE;
}
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) {
@Override
public void createMenu(SwipeMenu menu) {
if (mMenuCreator != null) {
mMenuCreator.create(menu);
}
}
@Override
public void onItemClick(SwipeMenuView view, SwipeMenu menu,
int index) {
boolean flag = false;
if (mOnMenuItemClickListener != null) {
flag = mOnMenuItemClickListener.onMenuItemClick(
view.getPosition(), menu, index);
}
if (mTouchView != null && !flag) {
mTouchView.smoothCloseMenu();
}
}
});
}
public void setCloseInterpolator(Interpolator interpolator) {
mCloseInterpolator = interpolator;
}
public void setOpenInterpolator(Interpolator interpolator) {
mOpenInterpolator = interpolator;
}
public Interpolator getOpenInterpolator() {
return mOpenInterpolator;
}
public Interpolator getCloseInterpolator() {
return mCloseInterpolator;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//在拦截处处理,在滑动设置了点击事件的地方也能swip,点击时又不能影响原来的点击事件
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: