使用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