前一篇文章写了怎么模拟桌面的滑动,这里分享一个模拟360安全卫士的滑动,主要是因为在网上看到有人问九宫格界面的滑动处理。
因为这样的界面里面有几个大大的块,这些块有点击事件,所以当在这个方块上面按下再左右滑动的时候,界面就不会跟着滑动了,因为这个事件已经被传递给滑动界面的子view了,滑动界面已经不再做出响应了。
解决的方法我参考了viewpager的源代码,自己做了简化,在原来模拟桌面滑动的代码基础上,完成了这个效果,效果图如下:
第一张图是滑动的效果,第二张图是点击的效果。
实现的方法就是重写onInterceptTouchEvent这个方法,这个方法的返回值表示当前的view要不要拦截用户的点击事件,true表示拦截,false表示不拦截,如果返回true则子view就不能得到点击事件。
这里不能简单的返回true或者false,因为我们需要拦截的是左右滑动的事件,而不是简单的点击事件,所以当用户的事件是一个简单的点击事件时就交给它的子view,如果是左右滑动的事件,则做拦截。
代码如下。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mIsScorlling = false;
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_UP) {
mIsScorlling = false;
return false;
}
switch (action) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
mLastMotionX = ev.getX();
mIsScorlling = false;
break;
case MotionEvent.ACTION_MOVE:
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
try {
final float x = ev.getX(pointerIndex);
final float deltaX = mLastMotionX - x;
mLastMotionX = x;
final float absDeltaX = Math.abs(deltaX);
if (absDeltaX > 6) {
mIsScorlling = true;
}
} catch (ArrayIndexOutOfBoundsException e) {
}
break;
}
return mIsScorlling;
}
这个较上一版的改动还有 如果滑到最后一个,就不能再往后划,如果在第一个,就不能往前滑,判断代码如下:
float downX = -1;
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mLastMotionX = ev.getX();
mActivePointerId = ev.getPointerId(0);
downX = mLastMotionX;
break;
case MotionEvent.ACTION_MOVE:
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
try {
final float x = ev.getX(pointerIndex);
final float deltaX = mLastMotionX - x;
mLastMotionX = x;
if (deltaX > 0) {
if (mCurrentViewIndex >= getChildCount() - 1) {
return true;
}
scrollBy((int) deltaX, 0);
} else if (deltaX < 0) {
if (mCurrentViewIndex <= 0) {
return true;
}
scrollBy((int) deltaX, 0);
} else {
awakenScrollBars();
}
} catch (ArrayIndexOutOfBoundsException e) {
}
break;
case MotionEvent.ACTION_UP:
int screenWidth = getWidth();
int whichView = (getScrollX() + (screenWidth / 2)) / screenWidth;
whichView = Math.max(0, Math.min(whichView, getChildCount() - 1));
int newX = whichView * getWidth();
int delta = newX - getScrollX();
mScroller.startScroll(getScrollX(), 0, delta, 0,
Math.abs(delta) * 2);
invalidate();
mCurrentViewIndex = whichView;
if (mViewIndexChangeLinstener != null) {
mViewIndexChangeLinstener.onIndexChange(whichView);
}
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
}
return true;
}
还有就是为了能让这个控件灵活地通知当前的索引,就是滑到第几个界面了,我将原来调用activity的静态方法改成通过回调的方式,代码如下:
public interface ViewIndexChangeLinstener {
public void onIndexChange(int whichView);
}
public void setViewIndexChangeLinstener(ViewIndexChangeLinstener linstener) {
this.mViewIndexChangeLinstener = linstener;
}
这个只是简单的提一下实现的方法,具体代码等我上传以后,在评论里面给出下载地址。