使用ViewPager作为一个页面进行切换,里面可以存放很多View,但有时在操作View时不小心滑动一下就有可能跳到下一页,这并不是我们想要的,这里就需要重写ViewPager修改它的滑动条件
效果图
程序目录结构
BTViewPager.java
package com.example.viewpagerdemo; import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.Scroller; /** * 解决ViewPager滑动过于灵敏,只有滑动距离大于100才滑到另一页 * * @author Administrator * */ public class BTViewPager extends ViewPager { private static final String TAG = "dzt_pager"; private static final int MOVE_LIMITATION = 100;// 触发移动的像素距离 private float mLastMotionX; // 手指触碰屏幕的最后一次x坐标 private int mCurScreen; private Scroller mScroller; // 滑动控件 public BTViewPager(Context context) { super(context); // TODO Auto-generated constructor stub init(context); } public BTViewPager(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(context); } private void init(Context context) { mScroller = new Scroller(context); mCurScreen = 0;// 默认设置显示第一个VIEW } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub final int action = event.getAction(); final float x = event.getX(); switch (action) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "[BTViewPager->]onTouchEvent ACTION_DOWN"); mLastMotionX = x; break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "[BTViewPager->]onTouchEvent ACTION_MOVE"); break; case MotionEvent.ACTION_UP: Log.d(TAG, "Item = " + getCurrentItem() + " count = " + getChildCount()); if (Math.abs(x - mLastMotionX) < MOVE_LIMITATION) { // snapToDestination(); // 跳到指定页 snapToScreen(getCurrentItem()); return true; } break; default: break; } Log.d(TAG, "[BTViewPager->]onTouchEvent--end"); return super.onTouchEvent(event); } @Override public void computeScroll() { // TODO Auto-generated method stub Log.d(TAG, "[BTViewPager->]computeScroll"); super.computeScroll(); if (mScroller.computeScrollOffset()) { Log.d(TAG, "[BTViewPager->]computeScroll x = " + mScroller.getCurrX()); scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } } /** * 根据滑动的距离判断移动到第几个视图 */ public void snapToDestination() { final int screenWidth = getWidth(); final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth; Log.d(TAG, "[BTViewPager->]snapToDestination screenWidth = " + screenWidth + " destScreen = " + destScreen); snapToScreen(destScreen); } /** * 滚动到制定的视图 * * @param whichScreen * 视图下标 */ public void snapToScreen(int whichScreen) { // whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - // 1)); if (getScrollX() != (whichScreen * getWidth())) { final int delta = whichScreen * getWidth() - getScrollX(); Log.d(TAG, "[BTViewPager->]snapToScreen-whichScreen = " + whichScreen + " delta = " + delta + " scrollX = " + getScrollX()); mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2); mCurScreen = whichScreen; invalidate(); } } /** * 用于拦截手势事件的,每个手势事件都会先调用这个方法。Layout里的onInterceptTouchEvent默认返回值是false, * 这样touch事件会传递到childview控件 ,如果返回false子控件可以响应,否则了控件不响应,这里主要是拦截子控件的响应, * 对ViewGroup不管返回值是什么都会执行onTouchEvent */ @Override public boolean onInterceptTouchEvent(MotionEvent arg0) { // TODO Auto-generated method stub Log.d(TAG, "[BTViewPager->]onInterceptTouchEvent"); final int action = arg0.getAction(); final float x = arg0.getX(); switch (action) { case MotionEvent.ACTION_DOWN: Log.d(TAG, "onInterceptTouchEvent---ACTION_DOWN "); mLastMotionX = x; break; case MotionEvent.ACTION_MOVE: Log.d(TAG, "onInterceptTouchEvent---ACTION_MOVE "); break; case MotionEvent.ACTION_UP: Log.d(TAG, "onInterceptTouchEvent---ACTION_UP "); break; default: break; } return super.onInterceptTouchEvent(arg0); } }只要是在onTouchEvent的UP中处理滑动的条件
if (Math.abs(x - mLastMotionX) < MOVE_LIMITATION) { // snapToDestination(); // 跳到指定页 snapToScreen(getCurrentItem()); return true; }只有滑动的距离大于100才进行上下页处理,否则就停在当前页,当前页使用getCurrentItem()获取,有一点要注意在ViewPager中getChildCount()获取的值是错误的,不清楚是什么原因,在ViewGroup中是有效的,这个可能要查看ViewPager源码才能弄清楚是什么原因,有知道的朋友可以告知我!
完整Demo:http://download.csdn.net/detail/deng0zhaotai/7384637