欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)閱讀APP平移翻頁(yè)效果

 更新時(shí)間:2022年05月10日 08:16:45   作者:陳靖_  
這篇文章主要介紹了Android實(shí)現(xiàn)閱讀APP平移翻頁(yè)效果的具體方法,模仿多看閱讀平移翻頁(yè),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

自己做的一個(gè)APP需要用到翻頁(yè)閱讀,網(wǎng)上看過(guò)立體翻頁(yè)效果,不過(guò)bug太多了還不兼容??戳艘幌露嗫撮喿x翻頁(yè)是采用平移翻頁(yè)的,于是就仿寫(xiě)了一個(gè)平移翻頁(yè)的控件。效果如下:

在翻頁(yè)時(shí)頁(yè)面右邊緣繪制了陰影,效果還不錯(cuò)。要實(shí)現(xiàn)這種平移翻頁(yè)控件并不難,只需要定義一個(gè)布局管理頁(yè)面就可以了。具體實(shí)現(xiàn)上有以下難點(diǎn):

    1、循環(huán)翻頁(yè),頁(yè)面的重復(fù)利用。

    2、在翻頁(yè)時(shí)過(guò)濾掉多點(diǎn)觸碰。

    3、采用setAdapter的方式設(shè)置頁(yè)面布局和數(shù)據(jù)。

下面就來(lái)一一解決這幾個(gè)難點(diǎn)。首先看循環(huán)翻頁(yè)問(wèn)題,怎么樣能采用較少的頁(yè)面實(shí)現(xiàn)這種翻頁(yè)呢?由于屏幕上每次只能顯示一張完整的頁(yè)面,翻過(guò)去的頁(yè)面也看不到,所以可以把翻過(guò)去的頁(yè)面拿來(lái)重復(fù)利用,不必每次都new一個(gè)頁(yè)面,所以,我只用了三張頁(yè)面實(shí)現(xiàn)循環(huán)翻頁(yè)。要想重復(fù)利用頁(yè)面,首先要知道頁(yè)面在布局中序號(hào)和對(duì)應(yīng)的層次關(guān)系,比如一個(gè)父控件的子view的序號(hào)越大就位于越上層。循環(huán)利用頁(yè)面的原理圖如下:

向右翻頁(yè)時(shí)狀態(tài)圖是這樣的,只用了0、1、2三張頁(yè)面,頁(yè)面序號(hào)為2的位于最上層,我把它隱藏在左邊,所以看到的只有頁(yè)面1,頁(yè)面0在1下面擋著也看不到,向右翻頁(yè)時(shí),頁(yè)面2被滑到屏幕中,這時(shí)候把頁(yè)面0的內(nèi)容替換成頁(yè)面2的前一頁(yè)內(nèi)容,把它放到之前頁(yè)面2的位置,這時(shí),狀態(tài)又回到了初始狀態(tài),又可以繼續(xù)向右翻頁(yè)了!

向左翻頁(yè)時(shí)是這樣的,初始狀態(tài)還是一樣,當(dāng)頁(yè)面1被往左翻過(guò)時(shí),看到的是頁(yè)面0,這時(shí)候頁(yè)面0下面已經(jīng)沒(méi)有頁(yè)面了,而頁(yè)面2已經(jīng)用不到了,這時(shí)候把頁(yè)面2放到頁(yè)面0下面,這時(shí)候狀態(tài)又回到了初始狀態(tài),就可以繼續(xù)往左翻頁(yè)了。

類(lèi)似于這種循環(huán)效果的實(shí)現(xiàn)我一直用的解決方案都是將選中的置于最中間,比如原理圖中的頁(yè)面1,每次翻頁(yè)完成后可見(jiàn)的都是頁(yè)面1。在滾動(dòng)選擇器PickerView中也是同樣的方案。這就解決了頁(yè)面的重復(fù)利用問(wèn)題了。

解決難點(diǎn)2 翻頁(yè)時(shí)過(guò)濾多點(diǎn)觸碰這個(gè)問(wèn)題在仿淘寶商品瀏覽界面中已經(jīng)解決過(guò)了,就是用一個(gè)控制變量mEvents過(guò)濾掉pointer down或up后到來(lái)的第一個(gè)move事件。

解決難點(diǎn)3 采用adapter方式設(shè)置頁(yè)面的布局和數(shù)據(jù)。這個(gè)在Android的AdapterView里用到的,但是我沒(méi)有看它的adapter機(jī)制,太復(fù)雜了,我就搞了個(gè)簡(jiǎn)單的adapter,如下:

PageAdapter.java:

package com.jingchen.pagerdemo; 
 
import android.view.View; 
 
public abstract class PageAdapter 
{ 
 /** 
  * @return 頁(yè)面view 
  */ 
 public abstract View getView(); 
 
 public abstract int getCount(); 
 
 /** 
  * 將內(nèi)容添加到view中 
  * 
  * @param view 
  *   包含內(nèi)容的view 
  * @param position 
  *   第position頁(yè) 
  */ 
 public abstract void addContent(View view, int position); 
} 

這是一個(gè)抽象類(lèi),getView()用于返回頁(yè)面的布局,getCount()返回?cái)?shù)據(jù)總共需要多少頁(yè),addContent(View view, int position)這個(gè)是每翻過(guò)一頁(yè)后將會(huì)被調(diào)用來(lái)請(qǐng)求頁(yè)面數(shù)據(jù)的,參數(shù)view就是頁(yè)面,position是表明第幾頁(yè)。待會(huì)兒會(huì)在自定義布局中定義setAdapter方法設(shè)置設(shè)配器。
OK,難點(diǎn)都解決了,自定義一個(gè)布局叫ScanView繼承自RelativeLayout:

ScanView.java:

package com.jingchen.pagerdemo; 
 
import java.util.Timer; 
import java.util.TimerTask; 
 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.LinearGradient; 
import android.graphics.Paint; 
import android.graphics.Paint.Style; 
import android.graphics.RectF; 
import android.graphics.Shader.TileMode; 
import android.os.Handler; 
import android.os.Message; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.VelocityTracker; 
import android.view.View; 
import android.widget.RelativeLayout; 
 
/** 
 * @author chenjing 
 * 
 */ 
public class ScanView extends RelativeLayout 
{ 
 public static final String TAG = "ScanView"; 
 private boolean isInit = true; 
 // 滑動(dòng)的時(shí)候存在兩頁(yè)可滑動(dòng),要判斷是哪一頁(yè)在滑動(dòng) 
 private boolean isPreMoving = true, isCurrMoving = true; 
 // 當(dāng)前是第幾頁(yè) 
 private int index; 
 private float lastX; 
 // 前一頁(yè),當(dāng)前頁(yè),下一頁(yè)的左邊位置 
 private int prePageLeft = 0, currPageLeft = 0, nextPageLeft = 0; 
 // 三張頁(yè)面 
 private View prePage, currPage, nextPage; 
 // 頁(yè)面狀態(tài) 
 private static final int STATE_MOVE = 0; 
 private static final int STATE_STOP = 1; 
 // 滑動(dòng)的頁(yè)面,只有前一頁(yè)和當(dāng)前頁(yè)可滑 
 private static final int PRE = 2; 
 private static final int CURR = 3; 
 private int state = STATE_STOP; 
 // 正在滑動(dòng)的頁(yè)面右邊位置,用于繪制陰影 
 private float right; 
 // 手指滑動(dòng)的距離 
 private float moveLenght; 
 // 頁(yè)面寬高 
 private int mWidth, mHeight; 
 // 獲取滑動(dòng)速度 
 private VelocityTracker vt; 
 // 防止抖動(dòng) 
 private float speed_shake = 20; 
 // 當(dāng)前滑動(dòng)速度 
 private float speed; 
 private Timer timer; 
 private MyTimerTask mTask; 
 // 滑動(dòng)動(dòng)畫(huà)的移動(dòng)速度 
 public static final int MOVE_SPEED = 10; 
 // 頁(yè)面適配器 
 private PageAdapter adapter; 
 /** 
 * 過(guò)濾多點(diǎn)觸碰的控制變量 
 */ 
 private int mEvents; 
 
 public void setAdapter(ScanViewAdapter adapter) 
 { 
 removeAllViews(); 
 this.adapter = adapter; 
 prePage = adapter.getView(); 
 addView(prePage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 adapter.addContent(prePage, index - 1); 
 
 currPage = adapter.getView(); 
 addView(currPage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 adapter.addContent(currPage, index); 
 
 nextPage = adapter.getView(); 
 addView(nextPage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 adapter.addContent(nextPage, index + 1); 
 
 } 
 
 /** 
 * 向左滑。注意可以滑動(dòng)的頁(yè)面只有當(dāng)前頁(yè)和前一頁(yè) 
 * 
 * @param which 
 */ 
 private void moveLeft(int which) 
 { 
 switch (which) 
 { 
 case PRE: 
 prePageLeft -= MOVE_SPEED; 
 if (prePageLeft < -mWidth) 
 prePageLeft = -mWidth; 
 right = mWidth + prePageLeft; 
 break; 
 case CURR: 
 currPageLeft -= MOVE_SPEED; 
 if (currPageLeft < -mWidth) 
 currPageLeft = -mWidth; 
 right = mWidth + currPageLeft; 
 break; 
 } 
 } 
 
 /** 
 * 向右滑。注意可以滑動(dòng)的頁(yè)面只有當(dāng)前頁(yè)和前一頁(yè) 
 * 
 * @param which 
 */ 
 private void moveRight(int which) 
 { 
 switch (which) 
 { 
 case PRE: 
 prePageLeft += MOVE_SPEED; 
 if (prePageLeft > 0) 
 prePageLeft = 0; 
 right = mWidth + prePageLeft; 
 break; 
 case CURR: 
 currPageLeft += MOVE_SPEED; 
 if (currPageLeft > 0) 
 currPageLeft = 0; 
 right = mWidth + currPageLeft; 
 break; 
 } 
 } 
 
 /** 
 * 當(dāng)往回翻過(guò)一頁(yè)時(shí)添加前一頁(yè)在最左邊 
 */ 
 private void addPrePage() 
 { 
 removeView(nextPage); 
 addView(nextPage, -1, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 // 從適配器獲取前一頁(yè)內(nèi)容 
 adapter.addContent(nextPage, index - 1); 
 // 交換順序 
 View temp = nextPage; 
 nextPage = currPage; 
 currPage = prePage; 
 prePage = temp; 
 prePageLeft = -mWidth; 
 } 
 
 /** 
 * 當(dāng)往前翻過(guò)一頁(yè)時(shí),添加一頁(yè)在最底下 
 */ 
 private void addNextPage() 
 { 
 removeView(prePage); 
 addView(prePage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 // 從適配器獲取后一頁(yè)內(nèi)容 
 adapter.addContent(prePage, index + 1); 
 // 交換順序 
 View temp = currPage; 
 currPage = nextPage; 
 nextPage = prePage; 
 prePage = temp; 
 currPageLeft = 0; 
 } 
 
 Handler updateHandler = new Handler() 
 { 
 
 @Override 
 public void handleMessage(Message msg) 
 { 
 if (state != STATE_MOVE) 
 return; 
 // 移動(dòng)頁(yè)面 
 // 翻回,先判斷當(dāng)前哪一頁(yè)處于未返回狀態(tài) 
 if (prePageLeft > -mWidth && speed <= 0) 
 { 
 // 前一頁(yè)處于未返回狀態(tài) 
 moveLeft(PRE); 
 } else if (currPageLeft < 0 && speed >= 0) 
 { 
 // 當(dāng)前頁(yè)處于未返回狀態(tài) 
 moveRight(CURR); 
 } else if (speed < 0 && index < adapter.getCount()) 
 { 
 // 向左翻,翻動(dòng)的是當(dāng)前頁(yè) 
 moveLeft(CURR); 
 if (currPageLeft == (-mWidth)) 
 { 
  index++; 
  // 翻過(guò)一頁(yè),在底下添加一頁(yè),把最上層頁(yè)面移除 
  addNextPage(); 
 } 
 } else if (speed > 0 && index > 1) 
 { 
 // 向右翻,翻動(dòng)的是前一頁(yè) 
 moveRight(PRE); 
 if (prePageLeft == 0) 
 { 
  index--; 
  // 翻回一頁(yè),添加一頁(yè)在最上層,隱藏在最左邊 
  addPrePage(); 
 } 
 } 
 if (right == 0 || right == mWidth) 
 { 
 releaseMoving(); 
 state = STATE_STOP; 
 quitMove(); 
 } 
 ScanView.this.requestLayout(); 
 } 
 
 }; 
 
 public ScanView(Context context, AttributeSet attrs, int defStyle) 
 { 
 super(context, attrs, defStyle); 
 init(); 
 } 
 
 public ScanView(Context context) 
 { 
 super(context); 
 init(); 
 } 
 
 public ScanView(Context context, AttributeSet attrs) 
 { 
 super(context, attrs); 
 init(); 
 } 
 
 /** 
 * 退出動(dòng)畫(huà)翻頁(yè) 
 */ 
 public void quitMove() 
 { 
 if (mTask != null) 
 { 
 mTask.cancel(); 
 mTask = null; 
 } 
 } 
 
 private void init() 
 { 
 index = 1; 
 timer = new Timer(); 
 mTask = new MyTimerTask(updateHandler); 
 } 
 
 /** 
 * 釋放動(dòng)作,不限制手滑動(dòng)方向 
 */ 
 private void releaseMoving() 
 { 
 isPreMoving = true; 
 isCurrMoving = true; 
 } 
 
 @Override 
 public boolean dispatchTouchEvent(MotionEvent event) 
 { 
 if (adapter != null) 
 switch (event.getActionMasked()) 
 { 
 case MotionEvent.ACTION_DOWN: 
 lastX = event.getX(); 
 try 
 { 
  if (vt == null) 
  { 
  vt = VelocityTracker.obtain(); 
  } else 
  { 
  vt.clear(); 
  } 
 } catch (Exception e) 
 { 
  e.printStackTrace(); 
 } 
 vt.addMovement(event); 
 mEvents = 0; 
 break; 
 case MotionEvent.ACTION_POINTER_DOWN: 
 case MotionEvent.ACTION_POINTER_UP: 
 mEvents = -1; 
 break; 
 case MotionEvent.ACTION_MOVE: 
 // 取消動(dòng)畫(huà) 
 quitMove(); 
 Log.d("index", "mEvents = " + mEvents + ", isPreMoving = " 
  + isPreMoving + ", isCurrMoving = " + isCurrMoving); 
 vt.addMovement(event); 
 vt.computeCurrentVelocity(500); 
 speed = vt.getXVelocity(); 
 moveLenght = event.getX() - lastX; 
 if ((moveLenght > 0 || !isCurrMoving) && isPreMoving 
  && mEvents == 0) 
 { 
  isPreMoving = true; 
  isCurrMoving = false; 
  if (index == 1) 
  { 
  // 第一頁(yè)不能再往右翻,跳轉(zhuǎn)到前一個(gè)activity 
  state = STATE_MOVE; 
  releaseMoving(); 
  } else 
  { 
  // 非第一頁(yè) 
  prePageLeft += (int) moveLenght; 
  // 防止滑過(guò)邊界 
  if (prePageLeft > 0) 
  prePageLeft = 0; 
  else if (prePageLeft < -mWidth) 
  { 
  // 邊界判斷,釋放動(dòng)作,防止來(lái)回滑動(dòng)導(dǎo)致滑動(dòng)前一頁(yè)時(shí)當(dāng)前頁(yè)無(wú)法滑動(dòng) 
  prePageLeft = -mWidth; 
  releaseMoving(); 
  } 
  right = mWidth + prePageLeft; 
  state = STATE_MOVE; 
  } 
 } else if ((moveLenght < 0 || !isPreMoving) && isCurrMoving 
  && mEvents == 0) 
 { 
  isPreMoving = false; 
  isCurrMoving = true; 
  if (index == adapter.getCount()) 
  { 
  // 最后一頁(yè)不能再往左翻 
  state = STATE_STOP; 
  releaseMoving(); 
  } else 
  { 
  currPageLeft += (int) moveLenght; 
  // 防止滑過(guò)邊界 
  if (currPageLeft < -mWidth) 
  currPageLeft = -mWidth; 
  else if (currPageLeft > 0) 
  { 
  // 邊界判斷,釋放動(dòng)作,防止來(lái)回滑動(dòng)導(dǎo)致滑動(dòng)當(dāng)前頁(yè)是前一頁(yè)無(wú)法滑動(dòng) 
  currPageLeft = 0; 
  releaseMoving(); 
  } 
  right = mWidth + currPageLeft; 
  state = STATE_MOVE; 
  } 
 
 } else 
  mEvents = 0; 
 lastX = event.getX(); 
 requestLayout(); 
 break; 
 case MotionEvent.ACTION_UP: 
 if (Math.abs(speed) < speed_shake) 
  speed = 0; 
 quitMove(); 
 mTask = new MyTimerTask(updateHandler); 
 timer.schedule(mTask, 0, 5); 
 try 
 { 
  vt.clear(); 
  vt.recycle(); 
 } catch (Exception e) 
 { 
  e.printStackTrace(); 
 } 
 break; 
 default: 
 break; 
 } 
 super.dispatchTouchEvent(event); 
 return true; 
 } 
 
 /* 
 * (非 Javadoc) 在這里繪制翻頁(yè)陰影效果 
 * 
 * @see android.view.ViewGroup#dispatchDraw(android.graphics.Canvas) 
 */ 
 @Override 
 protected void dispatchDraw(Canvas canvas) 
 { 
 super.dispatchDraw(canvas); 
 if (right == 0 || right == mWidth) 
 return; 
 RectF rectF = new RectF(right, 0, mWidth, mHeight); 
 Paint paint = new Paint(); 
 paint.setAntiAlias(true); 
 LinearGradient linearGradient = new LinearGradient(right, 0, 
 right + 36, 0, 0xffbbbbbb, 0x00bbbbbb, TileMode.CLAMP); 
 paint.setShader(linearGradient); 
 paint.setStyle(Style.FILL); 
 canvas.drawRect(rectF, paint); 
 } 
 
 @Override 
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
 { 
 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
 mWidth = getMeasuredWidth(); 
 mHeight = getMeasuredHeight(); 
 if (isInit) 
 { 
 // 初始狀態(tài),一頁(yè)放在左邊隱藏起來(lái),兩頁(yè)疊在一塊 
 prePageLeft = -mWidth; 
 currPageLeft = 0; 
 nextPageLeft = 0; 
 isInit = false; 
 } 
 } 
 
 @Override 
 protected void onLayout(boolean changed, int l, int t, int r, int b) 
 { 
 if (adapter == null) 
 return; 
 prePage.layout(prePageLeft, 0, 
 prePageLeft + prePage.getMeasuredWidth(), 
 prePage.getMeasuredHeight()); 
 currPage.layout(currPageLeft, 0, 
 currPageLeft + currPage.getMeasuredWidth(), 
 currPage.getMeasuredHeight()); 
 nextPage.layout(nextPageLeft, 0, 
 nextPageLeft + nextPage.getMeasuredWidth(), 
 nextPage.getMeasuredHeight()); 
 invalidate(); 
 } 
 
 class MyTimerTask extends TimerTask 
 { 
 Handler handler; 
 
 public MyTimerTask(Handler handler) 
 { 
 this.handler = handler; 
 } 
 
 @Override 
 public void run() 
 { 
 handler.sendMessage(handler.obtainMessage()); 
 } 
 
 } 
} 

代碼中的注釋寫(xiě)的非常多,原理理解了看代碼就容易看懂了。寫(xiě)完這個(gè)布局后再寫(xiě)一個(gè)ScanViewAdapter繼承PageAdapter:

package com.jingchen.pagerdemo; 
 
import java.util.Timer; 
import java.util.TimerTask; 
 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.LinearGradient; 
import android.graphics.Paint; 
import android.graphics.Paint.Style; 
import android.graphics.RectF; 
import android.graphics.Shader.TileMode; 
import android.os.Handler; 
import android.os.Message; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.VelocityTracker; 
import android.view.View; 
import android.widget.RelativeLayout; 
 
/** 
 * @author chenjing 
 * 
 */ 
public class ScanView extends RelativeLayout 
{ 
 public static final String TAG = "ScanView"; 
 private boolean isInit = true; 
 // 滑動(dòng)的時(shí)候存在兩頁(yè)可滑動(dòng),要判斷是哪一頁(yè)在滑動(dòng) 
 private boolean isPreMoving = true, isCurrMoving = true; 
 // 當(dāng)前是第幾頁(yè) 
 private int index; 
 private float lastX; 
 // 前一頁(yè),當(dāng)前頁(yè),下一頁(yè)的左邊位置 
 private int prePageLeft = 0, currPageLeft = 0, nextPageLeft = 0; 
 // 三張頁(yè)面 
 private View prePage, currPage, nextPage; 
 // 頁(yè)面狀態(tài) 
 private static final int STATE_MOVE = 0; 
 private static final int STATE_STOP = 1; 
 // 滑動(dòng)的頁(yè)面,只有前一頁(yè)和當(dāng)前頁(yè)可滑 
 private static final int PRE = 2; 
 private static final int CURR = 3; 
 private int state = STATE_STOP; 
 // 正在滑動(dòng)的頁(yè)面右邊位置,用于繪制陰影 
 private float right; 
 // 手指滑動(dòng)的距離 
 private float moveLenght; 
 // 頁(yè)面寬高 
 private int mWidth, mHeight; 
 // 獲取滑動(dòng)速度 
 private VelocityTracker vt; 
 // 防止抖動(dòng) 
 private float speed_shake = 20; 
 // 當(dāng)前滑動(dòng)速度 
 private float speed; 
 private Timer timer; 
 private MyTimerTask mTask; 
 // 滑動(dòng)動(dòng)畫(huà)的移動(dòng)速度 
 public static final int MOVE_SPEED = 10; 
 // 頁(yè)面適配器 
 private PageAdapter adapter; 
 /** 
 * 過(guò)濾多點(diǎn)觸碰的控制變量 
 */ 
 private int mEvents; 
 
 public void setAdapter(ScanViewAdapter adapter) 
 { 
 removeAllViews(); 
 this.adapter = adapter; 
 prePage = adapter.getView(); 
 addView(prePage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 adapter.addContent(prePage, index - 1); 
 
 currPage = adapter.getView(); 
 addView(currPage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 adapter.addContent(currPage, index); 
 
 nextPage = adapter.getView(); 
 addView(nextPage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 adapter.addContent(nextPage, index + 1); 
 
 } 
 
 /** 
 * 向左滑。注意可以滑動(dòng)的頁(yè)面只有當(dāng)前頁(yè)和前一頁(yè) 
 * 
 * @param which 
 */ 
 private void moveLeft(int which) 
 { 
 switch (which) 
 { 
 case PRE: 
 prePageLeft -= MOVE_SPEED; 
 if (prePageLeft < -mWidth) 
 prePageLeft = -mWidth; 
 right = mWidth + prePageLeft; 
 break; 
 case CURR: 
 currPageLeft -= MOVE_SPEED; 
 if (currPageLeft < -mWidth) 
 currPageLeft = -mWidth; 
 right = mWidth + currPageLeft; 
 break; 
 } 
 } 
 
 /** 
 * 向右滑。注意可以滑動(dòng)的頁(yè)面只有當(dāng)前頁(yè)和前一頁(yè) 
 * 
 * @param which 
 */ 
 private void moveRight(int which) 
 { 
 switch (which) 
 { 
 case PRE: 
 prePageLeft += MOVE_SPEED; 
 if (prePageLeft > 0) 
 prePageLeft = 0; 
 right = mWidth + prePageLeft; 
 break; 
 case CURR: 
 currPageLeft += MOVE_SPEED; 
 if (currPageLeft > 0) 
 currPageLeft = 0; 
 right = mWidth + currPageLeft; 
 break; 
 } 
 } 
 
 /** 
 * 當(dāng)往回翻過(guò)一頁(yè)時(shí)添加前一頁(yè)在最左邊 
 */ 
 private void addPrePage() 
 { 
 removeView(nextPage); 
 addView(nextPage, -1, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 // 從適配器獲取前一頁(yè)內(nèi)容 
 adapter.addContent(nextPage, index - 1); 
 // 交換順序 
 View temp = nextPage; 
 nextPage = currPage; 
 currPage = prePage; 
 prePage = temp; 
 prePageLeft = -mWidth; 
 } 
 
 /** 
 * 當(dāng)往前翻過(guò)一頁(yè)時(shí),添加一頁(yè)在最底下 
 */ 
 private void addNextPage() 
 { 
 removeView(prePage); 
 addView(prePage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 // 從適配器獲取后一頁(yè)內(nèi)容 
 adapter.addContent(prePage, index + 1); 
 // 交換順序 
 View temp = currPage; 
 currPage = nextPage; 
 nextPage = prePage; 
 prePage = temp; 
 currPageLeft = 0; 
 } 
 
 Handler updateHandler = new Handler() 
 { 
 
 @Override 
 public void handleMessage(Message msg) 
 { 
 if (state != STATE_MOVE) 
 return; 
 // 移動(dòng)頁(yè)面 
 // 翻回,先判斷當(dāng)前哪一頁(yè)處于未返回狀態(tài) 
 if (prePageLeft > -mWidth && speed <= 0) 
 { 
 // 前一頁(yè)處于未返回狀態(tài) 
 moveLeft(PRE); 
 } else if (currPageLeft < 0 && speed >= 0) 
 { 
 // 當(dāng)前頁(yè)處于未返回狀態(tài) 
 moveRight(CURR); 
 } else if (speed < 0 && index < adapter.getCount()) 
 { 
 // 向左翻,翻動(dòng)的是當(dāng)前頁(yè) 
 moveLeft(CURR); 
 if (currPageLeft == (-mWidth)) 
 { 
  index++; 
  // 翻過(guò)一頁(yè),在底下添加一頁(yè),把最上層頁(yè)面移除 
  addNextPage(); 
 } 
 } else if (speed > 0 && index > 1) 
 { 
 // 向右翻,翻動(dòng)的是前一頁(yè) 
 moveRight(PRE); 
 if (prePageLeft == 0) 
 { 
  index--; 
  // 翻回一頁(yè),添加一頁(yè)在最上層,隱藏在最左邊 
  addPrePage(); 
 } 
 } 
 if (right == 0 || right == mWidth) 
 { 
 releaseMoving(); 
 state = STATE_STOP; 
 quitMove(); 
 } 
 ScanView.this.requestLayout(); 
 } 
 
 }; 
 
 public ScanView(Context context, AttributeSet attrs, int defStyle) 
 { 
 super(context, attrs, defStyle); 
 init(); 
 } 
 
 public ScanView(Context context) 
 { 
 super(context); 
 init(); 
 } 
 
 public ScanView(Context context, AttributeSet attrs) 
 { 
 super(context, attrs); 
 init(); 
 } 
 
 /** 
 * 退出動(dòng)畫(huà)翻頁(yè) 
 */ 
 public void quitMove() 
 { 
 if (mTask != null) 
 { 
 mTask.cancel(); 
 mTask = null; 
 } 
 } 
 
 private void init() 
 { 
 index = 1; 
 timer = new Timer(); 
 mTask = new MyTimerTask(updateHandler); 
 } 
 
 /** 
 * 釋放動(dòng)作,不限制手滑動(dòng)方向 
 */ 
 private void releaseMoving() 
 { 
 isPreMoving = true; 
 isCurrMoving = true; 
 } 
 
 @Override 
 public boolean dispatchTouchEvent(MotionEvent event) 
 { 
 if (adapter != null) 
 switch (event.getActionMasked()) 
 { 
 case MotionEvent.ACTION_DOWN: 
 lastX = event.getX(); 
 try 
 { 
  if (vt == null) 
  { 
  vt = VelocityTracker.obtain(); 
  } else 
  { 
  vt.clear(); 
  } 
 } catch (Exception e) 
 { 
  e.printStackTrace(); 
 } 
 vt.addMovement(event); 
 mEvents = 0; 
 break; 
 case MotionEvent.ACTION_POINTER_DOWN: 
 case MotionEvent.ACTION_POINTER_UP: 
 mEvents = -1; 
 break; 
 case MotionEvent.ACTION_MOVE: 
 // 取消動(dòng)畫(huà) 
 quitMove(); 
 Log.d("index", "mEvents = " + mEvents + ", isPreMoving = " 
  + isPreMoving + ", isCurrMoving = " + isCurrMoving); 
 vt.addMovement(event); 
 vt.computeCurrentVelocity(500); 
 speed = vt.getXVelocity(); 
 moveLenght = event.getX() - lastX; 
 if ((moveLenght > 0 || !isCurrMoving) && isPreMoving 
  && mEvents == 0) 
 { 
  isPreMoving = true; 
  isCurrMoving = false; 
  if (index == 1) 
  { 
  // 第一頁(yè)不能再往右翻,跳轉(zhuǎn)到前一個(gè)activity 
  state = STATE_MOVE; 
  releaseMoving(); 
  } else 
  { 
  // 非第一頁(yè) 
  prePageLeft += (int) moveLenght; 
  // 防止滑過(guò)邊界 
  if (prePageLeft > 0) 
  prePageLeft = 0; 
  else if (prePageLeft < -mWidth) 
  { 
  // 邊界判斷,釋放動(dòng)作,防止來(lái)回滑動(dòng)導(dǎo)致滑動(dòng)前一頁(yè)時(shí)當(dāng)前頁(yè)無(wú)法滑動(dòng) 
  prePageLeft = -mWidth; 
  releaseMoving(); 
  } 
  right = mWidth + prePageLeft; 
  state = STATE_MOVE; 
  } 
 } else if ((moveLenght < 0 || !isPreMoving) && isCurrMoving 
  && mEvents == 0) 
 { 
  isPreMoving = false; 
  isCurrMoving = true; 
  if (index == adapter.getCount()) 
  { 
  // 最后一頁(yè)不能再往左翻 
  state = STATE_STOP; 
  releaseMoving(); 
  } else 
  { 
  currPageLeft += (int) moveLenght; 
  // 防止滑過(guò)邊界 
  if (currPageLeft < -mWidth) 
  currPageLeft = -mWidth; 
  else if (currPageLeft > 0) 
  { 
  // 邊界判斷,釋放動(dòng)作,防止來(lái)回滑動(dòng)導(dǎo)致滑動(dòng)當(dāng)前頁(yè)是前一頁(yè)無(wú)法滑動(dòng) 
  currPageLeft = 0; 
  releaseMoving(); 
  } 
  right = mWidth + currPageLeft; 
  state = STATE_MOVE; 
  } 
 
 } else 
  mEvents = 0; 
 lastX = event.getX(); 
 requestLayout(); 
 break; 
 case MotionEvent.ACTION_UP: 
 if (Math.abs(speed) < speed_shake) 
  speed = 0; 
 quitMove(); 
 mTask = new MyTimerTask(updateHandler); 
 timer.schedule(mTask, 0, 5); 
 try 
 { 
  vt.clear(); 
  vt.recycle(); 
 } catch (Exception e) 
 { 
  e.printStackTrace(); 
 } 
 break; 
 default: 
 break; 
 } 
 super.dispatchTouchEvent(event); 
 return true; 
 } 
 
 /* 
 * (非 Javadoc) 在這里繪制翻頁(yè)陰影效果 
 * 
 * @see android.view.ViewGroup#dispatchDraw(android.graphics.Canvas) 
 */ 
 @Override 
 protected void dispatchDraw(Canvas canvas) 
 { 
 super.dispatchDraw(canvas); 
 if (right == 0 || right == mWidth) 
 return; 
 RectF rectF = new RectF(right, 0, mWidth, mHeight); 
 Paint paint = new Paint(); 
 paint.setAntiAlias(true); 
 LinearGradient linearGradient = new LinearGradient(right, 0, 
 right + 36, 0, 0xffbbbbbb, 0x00bbbbbb, TileMode.CLAMP); 
 paint.setShader(linearGradient); 
 paint.setStyle(Style.FILL); 
 canvas.drawRect(rectF, paint); 
 } 
 
 @Override 
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
 { 
 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
 mWidth = getMeasuredWidth(); 
 mHeight = getMeasuredHeight(); 
 if (isInit) 
 { 
 // 初始狀態(tài),一頁(yè)放在左邊隱藏起來(lái),兩頁(yè)疊在一塊 
 prePageLeft = -mWidth; 
 currPageLeft = 0; 
 nextPageLeft = 0; 
 isInit = false; 
 } 
 } 
 
 @Override 
 protected void onLayout(boolean changed, int l, int t, int r, int b) 
 { 
 if (adapter == null) 
 return; 
 prePage.layout(prePageLeft, 0, 
 prePageLeft + prePage.getMeasuredWidth(), 
 prePage.getMeasuredHeight()); 
 currPage.layout(currPageLeft, 0, 
 currPageLeft + currPage.getMeasuredWidth(), 
 currPage.getMeasuredHeight()); 
 nextPage.layout(nextPageLeft, 0, 
 nextPageLeft + nextPage.getMeasuredWidth(), 
 nextPage.getMeasuredHeight()); 
 invalidate(); 
 } 
 
 class MyTimerTask extends TimerTask 
 { 
 Handler handler; 
 
 public MyTimerTask(Handler handler) 
 { 
 this.handler = handler; 
 } 
 
 @Override 
 public void run() 
 { 
 handler.sendMessage(handler.obtainMessage()); 
 } 
 
 } 
} 

這里只是我的demo里寫(xiě)的Adapter,也可以寫(xiě)成帶更多內(nèi)容的Adapter。addContent里帶的參數(shù)view就是getView里面返回的view,這樣就可以根據(jù)inflate的布局設(shè)置內(nèi)容了,getView返回的布局page_layout.xml如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="@drawable/cover" > 
 
 <TextView 
 android:id="@+id/content" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_centerHorizontal="true" 
 android:layout_marginTop="60dp" 
 android:padding="10dp" 
 android:textColor="#000000" 
 android:textSize="22sp" /> 
 
 <TextView 
 android:id="@+id/index" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_alignParentBottom="true" 
 android:layout_centerHorizontal="true" 
 android:layout_marginBottom="60dp" 
 android:textColor="#000000" 
 android:textSize="30sp" /> 
 
</RelativeLayout> 

只包含了兩個(gè)TextView,所以在adapter中可以根據(jù)id查找到這兩個(gè)TextView再給它設(shè)置內(nèi)容。
OK了,MainActivity的布局如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="@drawable/cover" > 
 
 <TextView 
 android:id="@+id/content" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_centerHorizontal="true" 
 android:layout_marginTop="60dp" 
 android:padding="10dp" 
 android:textColor="#000000" 
 android:textSize="22sp" /> 
 
 <TextView 
 android:id="@+id/index" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_alignParentBottom="true" 
 android:layout_centerHorizontal="true" 
 android:layout_marginBottom="60dp" 
 android:textColor="#000000" 
 android:textSize="30sp" /> 
 
</RelativeLayout> 

很簡(jiǎn)單,只包含了ScanView。
MainActivity的代碼:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="@drawable/cover" > 
 
 <TextView 
 android:id="@+id/content" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_centerHorizontal="true" 
 android:layout_marginTop="60dp" 
 android:padding="10dp" 
 android:textColor="#000000" 
 android:textSize="22sp" /> 
 
 <TextView 
 android:id="@+id/index" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_alignParentBottom="true" 
 android:layout_centerHorizontal="true" 
 android:layout_marginBottom="60dp" 
 android:textColor="#000000" 
 android:textSize="30sp" /> 
 
</RelativeLayout> 

給ScanView設(shè)置Adapter就可以了。
好啦,仿多看的平移翻頁(yè)就完成了。

希望本文對(duì)大家學(xué)習(xí)Android軟件編程有所幫助。

相關(guān)文章

最新評(píng)論