大概在今年1月份吧,项目中有需要用到pulltorefresh+swipmenulistview,但是这两个控件整合到一块,在网上找了好久都没找到好的,要么是整合的不好,要么是直接重写swipmenulistview控件来实现下拉刷新的功能
于是我就把两个控件整合到了一起,以后项目想用的时候就很方便了哈~ 先看看如下效果
是不是很爽?!接下来我就分析其中的原理,细节性的我就不说,我就大概给个思路和一些关键性代码,细节性的大家就去下源码看看吧~
先分析下,上拉和下拉操作都要给pulltorefresh处理,左滑和右滑都要交给swipmenulistview,然后swipmenulistview的父布局是pulltorefresh,刚开始整合的时候很容易,功能也能实现,但是用户体验非常差,例如swipmenulistview左滑和右滑时,如果滑动时,Y轴方向的移动距离达到触发下拉事件的话,左右滑动就会停止,滑动事件被pulltorefresh进行处理,导致左右滑动就无法进行了
既然原因知道了,然后需要根据Touch事件的分发处理机制,那问题很容易解决,在swipmenulistview进行滑动时,所有的滑动事件都交由swipmenulistview处理就行,但是根据Touch事件的触发机制,是从外到内,即父布局传到子布局,这里的父布局就是pulltorefresh,子布局就是swipmenulistview。 一旦swipmenulistview进行滑动了,那么在swipmenulistview滑动事件未处理完毕之前,所有的Touch事件都交由swipmenulistview进行处理,思路就是这样子 接下来看一些修改的关键性代码
首先swipmenulistview需要暴露一个接口,来让父布局即pulltorefresh监听它的当前状态,pulltorefresh根据swipmenulistview状态是否将Touch事件传递下去
在SwipeMenuListView这个类中,有这么个属性
private int mTouchPosition;它就是代表着当前swipmenulistview的状态,下面这三个属性,分别代表当前swipmenulistview的状态,TOUCH_STATE_X代表现在是左右滑动中,在这个状态中,所有的Touch事件需要它处理,父布局不能处理
private static final int TOUCH_STATE_NONE = 0; private static final int TOUCH_STATE_X = 1; private static final int TOUCH_STATE_Y = 2;
现在 就是关键的部分,就是在SwipeMenuListView进行滑动时,实时改写mTouchPosition的状态,然后父布局根据这个状态是否需要处理当前的Touch事件
首先如何动态改写:覆写SwipeMenuListView的onTouchEvent(MotionEvent ev),如下代码
public boolean onTouchEvent(MotionEvent ev) {
int action = MotionEventCompat.getActionMasked(ev);
action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getX();
mDownY = ev.getY();
mTouchState = TOUCH_STATE_NONE;//重置当前状态
if (mTouchView != null && mTouchView.isOpen()) {
mTouchView.smoothCloseMenu();
return false;
}
mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
View view = getChildAt(mTouchPosition - getFirstVisiblePosition());
if (view instanceof SwipeMenuLayout) {
mTouchView = (SwipeMenuLayout) view;
mTouchView.setmSwipeStateListen(new SwipeMenuLayout.SwipeStateListen() {
@Override
public void stateChange() {
mTouchState = TOUCH_STATE_NONE;
}
});
}
if (mTouchView != null) {
mTouchView.onSwipe(ev);
}
break;
case MotionEvent.ACTION_MOVE:
float dy = Math.abs((ev.getY() - mDownY));
float dx = Math.abs((ev.getX() - mDownX));
if (mTouchState == TOUCH_STATE_X) {
// 滑动
if (mTouchView != null) {
mTouchView.onSwipe(ev);
}
getSelector().setState(new int[]{0});
ev.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(ev);
return true;
} else {
// Log.i("byz", "state = " + mTouchState + ", dx = " + dx
// + ", max = " + MAX_X);
if (mTouchState != TOUCH_STATE_X && Math.abs(dy) > MAX_Y) {//是左右滑动,改写状态为TOUCH_STATE_X
mTouchState = TOUCH_STATE_Y;
}
if (mTouchState != TOUCH_STATE_Y && dx > MAX_X) {//是左右滑动,改写状态为TOUCH_STATE_Y
mTouchState = TOUCH_STATE_X;
}
}
break;
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_X) {//将滑动动画播放完毕
if (mTouchView != null) {
mTouchView.onSwipe(ev);
}
ev.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(ev);
return true;
}
break;
}
return super.onTouchEvent(ev);
}
状态已经实时改写,现在就是在pulltorefresh的onInterceptTouchEvent(MotionEvent event)方法中进行事件的分发操作,pulltorefresh根据状态为1的就进行事件下发,自己不处理,如下代码
@Override
public final boolean onInterceptTouchEvent(MotionEvent event) {
if (mListView.getmTouchState() == 1) {
return false;
}
return super.onInterceptTouchEvent(event);
}
pulltorefresh这个控件相信在很多项目都有使用过,即防ios的下拉刷新效果~下载地址
swipmenulistview 这个控件也是仿ios的item的左滑效果,以有更多功能选项 下载地址
整合swipmenulistview+pulltorefresh 点击打开链接,如果打不开,可以私信我~(项目是用Gradle构建,最好用as打开)