안 드 로 이 드 는 읽 기 APP 페 이 징 효과 구현

자신 이 만 든 앱 은 페이지 를 넘 겨 읽 고 인터넷 에서 입체 적 인 페이지 넘 기 효 과 를 봐 야 하지만 bug 가 너무 많아 서 호 환 되 지 않 습 니 다.많이 보 았 습 니 다.효 과 는 다음 과 같 습 니 다:

페이지 를 넘 길 때 페이지 오른쪽 가장자리 에 그림자 가 그 려 져 효과 가 좋 습 니 다.이러한 페 이 징 컨트롤 을 실현 하 는 것 은 어렵 지 않 습 니 다.레이아웃 관리 페이지 만 정의 하면 됩 니 다.구체 적 인 실현 에는 다음 과 같은 난점 이 있다.
    1.반복 적 으로 페이지 를 넘 기 고 페이지 의 중복 이용.
    2.페이지 를 넘 길 때 여러 개의 접촉 을 걸 러 냅 니 다.
    3.setAdapter 방식 으로 페이지 레이아웃 과 데 이 터 를 설정 합 니 다.
다음은 이 몇 가지 난점 을 하나하나 해결 하 겠 습 니 다.우선 순환 페이지 넘 기 문 제 를 살 펴 보면 어떻게 비교적 적은 페이지 로 이런 페이지 넘 기 를 실현 할 수 있 습 니까?화면 에 매번 완전한 페이지 만 표시 되 고 넘 어 가 는 페이지 도 보이 지 않 기 때문에 넘 어 가 는 페이지 를 다시 이용 할 수 있 습 니 다.매번 새로운 페이지 가 필요 하지 않 습 니 다.그래서 저 는 세 페이지 만 사용 하여 순환 적 으로 페이지 를 넘 겼 습 니 다.페이지 를 반복 적 으로 이용 하려 면 먼저 페이지 가 레이아웃 에서 번호 와 대응 하 는 차원 관 계 를 알 아야 한다.예 를 들 어 부모 컨트롤 의 하위 view 의 번호 가 클 수록 상층 부 에 있다.페이지 를 순환 적 으로 이용 하 는 원리 도 는 다음 과 같다.
오른쪽으로 페이지 를 넘 길 때 상태 도 는 이 렇 습 니 다.0,1,2 세 페이지 만 사 용 했 습 니 다.페이지 번호 가 2 인 것 은 맨 위 에 있 습 니 다.제 가 왼쪽 에 숨 겼 기 때문에 보 이 는 것 은 페이지 1 뿐 입 니 다.페이지 0 은 1 아래 에서 가 려 도 보이 지 않 습 니 다.오른쪽으로 페이지 를 넘 길 때 페이지 2 는 화면 에 미 끄 러 졌 습 니 다.이때 페이지 0 의 내용 을 페이지 2 의 앞 페이지 내용 으로 바 꾸 었 습 니 다.이전 페이지 2 의 위치 에 놓 으 면 상태 가 다시 초기 상태 로 돌아 가 오른쪽 으로 계속 넘 길 수 있 습 니 다!

왼쪽으로 페이지 를 넘 길 때 는 이 렇 습 니 다.초기 상 태 는 똑 같 습 니 다.페이지 1 이 왼쪽으로 넘 어 졌 을 때 페이지 0 을 보 았 습 니 다.이때 페이지 0 아래 에는 페이지 가 없 었 고 페이지 2 는 사용 할 수 없 었 습 니 다.이때 페이지 2 를 페이지 0 아래 에 놓 았 습 니 다.이때 상태 가 다시 초기 상태 로 돌아 가면 계속 왼쪽으로 페이지 를 넘 길 수 있 습 니 다.

이러한 순환 효과 의 실현 과 비슷 하 게 제 가 사용 해 온 해결 방안 은 모두 선택 한 것 을 가장 중간 에 두 는 것 입 니 다.예 를 들 어 원리 그림 의 페이지 1 은 페이지 를 넘 길 때마다 볼 수 있 는 것 은 모두 페이지 1 입 니 다.스크롤 선택 기 PickerView에서 도 같은 방안 이다.이것 은 페이지 의 중복 이용 문 제 를 해결 했다.
어 려 운 점 2 페이지 를 넘 길 때 다 중 터치 문 제 를 걸 러 내 는 것 은가짜 타 오 바 오 상품 탐색 창에서 해결 되 었 습 니 다.제어 변수 mEvents 로 pointer down 이나 up 을 걸 러 낸 첫 번 째 move 사건 입 니 다.
난점 해결 3 adapter 방식 으로 페이지 의 레이아웃 과 데 이 터 를 설정 합 니 다.이것 은 Android 의 AdapterView 에 사 용 됩 니 다.그러나 저 는 adapter 체 제 를 보지 않 았 습 니 다.너무 복잡 해서 저 는 간단 한 adapter 를 만 들 었 습 니 다.다음 과 같 습 니 다.
PageAdapter.java:

package com.jingchen.pagerdemo; 
 
import android.view.View; 
 
public abstract class PageAdapter 
{ 
 /** 
  * @return   view 
  */ 
 public abstract View getView(); 
 
 public abstract int getCount(); 
 
 /** 
  *       view  
  * 
  * @param view 
  *        view 
  * @param position 
  *    position  
  */ 
 public abstract void addContent(View view, int position); 
} 
이것 은 추상 적 인 클래스 입 니 다.getView()는 페이지 의 레이아웃 을 되 돌려 주 는 데 사 용 됩 니 다.getCount()는 데 이 터 를 되 돌려 주 는 데 총 몇 페이지 가 필요 합 니까?addContent(View view,int position)는 한 페이지 를 넘 길 때마다 페이지 데 이 터 를 요청 하 는 데 사 용 됩 니 다.매개 변수 view 는 페이지 이 고 position 는 몇 페이지 를 표시 합 니 다.잠시 후 사용자 정의 레이아웃 에서 setAdapter 방법 설정 기 를 정의 합 니 다.
OK,어 려 운 점 이 모두 해결 되 었 습 니 다.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; 
 //             ,           
 private boolean isPreMoving = true, isCurrMoving = true; 
 //        
 private int index; 
 private float lastX; 
 //    ,   ,         
 private int prePageLeft = 0, currPageLeft = 0, nextPageLeft = 0; 
 //      
 private View prePage, currPage, nextPage; 
 //      
 private static final int STATE_MOVE = 0; 
 private static final int STATE_STOP = 1; 
 //      ,            
 private static final int PRE = 2; 
 private static final int CURR = 3; 
 private int state = STATE_STOP; 
 //            ,       
 private float right; 
 //         
 private float moveLenght; 
 //      
 private int mWidth, mHeight; 
 //        
 private VelocityTracker vt; 
 //      
 private float speed_shake = 20; 
 //        
 private float speed; 
 private Timer timer; 
 private MyTimerTask mTask; 
 //           
 public static final int MOVE_SPEED = 10; 
 //       
 private PageAdapter adapter; 
 /** 
 *             
 */ 
 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); 
 
 } 
 
 /** 
 *    。                   
 * 
 * @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; 
 } 
 } 
 
 /** 
 *    。                   
 * 
 * @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; 
 } 
 } 
 
 /** 
 *                   
 */ 
 private void addPrePage() 
 { 
 removeView(nextPage); 
 addView(nextPage, -1, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 //             
 adapter.addContent(nextPage, index - 1); 
 //      
 View temp = nextPage; 
 nextPage = currPage; 
 currPage = prePage; 
 prePage = temp; 
 prePageLeft = -mWidth; 
 } 
 
 /** 
 *         ,         
 */ 
 private void addNextPage() 
 { 
 removeView(prePage); 
 addView(prePage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 //             
 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; 
 //      
 //   ,                
 if (prePageLeft > -mWidth && speed <= 0) 
 { 
 //            
 moveLeft(PRE); 
 } else if (currPageLeft < 0 && speed >= 0) 
 { 
 //            
 moveRight(CURR); 
 } else if (speed < 0 && index < adapter.getCount()) 
 { 
 //    ,        
 moveLeft(CURR); 
 if (currPageLeft == (-mWidth)) 
 { 
  index++; 
  //     ,       ,         
  addNextPage(); 
 } 
 } else if (speed > 0 && index > 1) 
 { 
 //    ,        
 moveRight(PRE); 
 if (prePageLeft == 0) 
 { 
  index--; 
  //     ,        ,       
  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(); 
 } 
 
 /** 
 *        
 */ 
 public void quitMove() 
 { 
 if (mTask != null) 
 { 
 mTask.cancel(); 
 mTask = null; 
 } 
 } 
 
 private void init() 
 { 
 index = 1; 
 timer = new Timer(); 
 mTask = new MyTimerTask(updateHandler); 
 } 
 
 /** 
 *     ,         
 */ 
 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: 
 //      
 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) 
  { 
  //          ,      activity 
  state = STATE_MOVE; 
  releaseMoving(); 
  } else 
  { 
  //      
  prePageLeft += (int) moveLenght; 
  //        
  if (prePageLeft > 0) 
  prePageLeft = 0; 
  else if (prePageLeft < -mWidth) 
  { 
  //     ,    ,                      
  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()) 
  { 
  //            
  state = STATE_STOP; 
  releaseMoving(); 
  } else 
  { 
  currPageLeft += (int) moveLenght; 
  //        
  if (currPageLeft < -mWidth) 
  currPageLeft = -mWidth; 
  else if (currPageLeft > 0) 
  { 
  //     ,    ,                      
  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)             
 * 
 * @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) 
 { 
 //     ,          ,       
 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()); 
 } 
 
 } 
} 
코드 에 주석 이 매우 많아 서 원 리 를 이해 하면 코드 를 보면 쉽게 이해 할 수 있다.이 레이아웃 을 다 쓴 다음 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; 
 //             ,           
 private boolean isPreMoving = true, isCurrMoving = true; 
 //        
 private int index; 
 private float lastX; 
 //    ,   ,         
 private int prePageLeft = 0, currPageLeft = 0, nextPageLeft = 0; 
 //      
 private View prePage, currPage, nextPage; 
 //      
 private static final int STATE_MOVE = 0; 
 private static final int STATE_STOP = 1; 
 //      ,            
 private static final int PRE = 2; 
 private static final int CURR = 3; 
 private int state = STATE_STOP; 
 //            ,       
 private float right; 
 //         
 private float moveLenght; 
 //      
 private int mWidth, mHeight; 
 //        
 private VelocityTracker vt; 
 //      
 private float speed_shake = 20; 
 //        
 private float speed; 
 private Timer timer; 
 private MyTimerTask mTask; 
 //           
 public static final int MOVE_SPEED = 10; 
 //       
 private PageAdapter adapter; 
 /** 
 *             
 */ 
 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); 
 
 } 
 
 /** 
 *    。                   
 * 
 * @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; 
 } 
 } 
 
 /** 
 *    。                   
 * 
 * @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; 
 } 
 } 
 
 /** 
 *                   
 */ 
 private void addPrePage() 
 { 
 removeView(nextPage); 
 addView(nextPage, -1, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 //             
 adapter.addContent(nextPage, index - 1); 
 //      
 View temp = nextPage; 
 nextPage = currPage; 
 currPage = prePage; 
 prePage = temp; 
 prePageLeft = -mWidth; 
 } 
 
 /** 
 *         ,         
 */ 
 private void addNextPage() 
 { 
 removeView(prePage); 
 addView(prePage, 0, new LayoutParams(LayoutParams.MATCH_PARENT, 
 LayoutParams.MATCH_PARENT)); 
 //             
 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; 
 //      
 //   ,                
 if (prePageLeft > -mWidth && speed <= 0) 
 { 
 //            
 moveLeft(PRE); 
 } else if (currPageLeft < 0 && speed >= 0) 
 { 
 //            
 moveRight(CURR); 
 } else if (speed < 0 && index < adapter.getCount()) 
 { 
 //    ,        
 moveLeft(CURR); 
 if (currPageLeft == (-mWidth)) 
 { 
  index++; 
  //     ,       ,         
  addNextPage(); 
 } 
 } else if (speed > 0 && index > 1) 
 { 
 //    ,        
 moveRight(PRE); 
 if (prePageLeft == 0) 
 { 
  index--; 
  //     ,        ,       
  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(); 
 } 
 
 /** 
 *        
 */ 
 public void quitMove() 
 { 
 if (mTask != null) 
 { 
 mTask.cancel(); 
 mTask = null; 
 } 
 } 
 
 private void init() 
 { 
 index = 1; 
 timer = new Timer(); 
 mTask = new MyTimerTask(updateHandler); 
 } 
 
 /** 
 *     ,         
 */ 
 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: 
 //      
 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) 
  { 
  //          ,      activity 
  state = STATE_MOVE; 
  releaseMoving(); 
  } else 
  { 
  //      
  prePageLeft += (int) moveLenght; 
  //        
  if (prePageLeft > 0) 
  prePageLeft = 0; 
  else if (prePageLeft < -mWidth) 
  { 
  //     ,    ,                      
  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()) 
  { 
  //            
  state = STATE_STOP; 
  releaseMoving(); 
  } else 
  { 
  currPageLeft += (int) moveLenght; 
  //        
  if (currPageLeft < -mWidth) 
  currPageLeft = -mWidth; 
  else if (currPageLeft > 0) 
  { 
  //     ,    ,                      
  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)             
 * 
 * @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) 
 { 
 //     ,          ,       
 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 에 쓰 인 Adapter 일 뿐 더 많은 내용 을 가 진 Adapter 로 쓸 수 있 습 니 다.addContent 에 있 는 매개 변수 view 는 getView 에서 돌아 오 는 view 입 니 다.그러면 inflate 의 레이아웃 에 따라 내용 을 설정 할 수 있 습 니 다.getView 가 돌아 오 는 레이아웃 pagelayout.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> 
두 개의 TextView 만 포함 되 어 있 기 때문에 adapter 에서 id 에 따라 이 두 개의 TextView 를 찾 아 내용 을 설정 할 수 있 습 니 다.
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> 
간단 합 니 다.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 에 Adapter 를 설정 하면 됩 니 다.
자,많이 본 것 을 본 떠 서 페이지 를 넘 기 면 됩 니 다.
본 고 는 여러분 들 이 안 드 로 이 드 소프트웨어 프로 그래 밍 을 배 우 는 데 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기