| 
 | 
 
| 
 
 package com.newBook; 
 
/* 
* Copyright (c) 2010  
* 
* Author: Wallace Wang 
* Email: wallage@qq.com 
*/ 
 
import java.util.Date; 
 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.LinearGradient; 
import android.graphics.Matrix; 
import android.graphics.Paint; 
import android.graphics.Path; 
import android.graphics.Point; 
import android.graphics.PorterDuffXfermode; 
import android.graphics.Shader; 
import android.graphics.PorterDuff.Mode; 
import android.os.Handler; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.GestureDetector; 
import android.view.MotionEvent; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import android.view.View; 
import android.view.GestureDetector.OnGestureListener; 
import android.widget.FrameLayout; 
import android.widget.LinearLayout; 
 
public class eBook extends FrameLayout{ 
public static final String LOG_TAG = "eBook"; 
int totalPageNum; 
Context mContext; 
boolean hasInit = false; 
final int defaultWidth = 600 , defaultHeight = 400; 
int contentWidth = 0; 
int contentHeight = 0; 
View leftPage,rightPage,llPage,lrPage,rrPage,rlPage; 
LinearLayout invisibleView; 
LinearLayout mView; 
MidView mMidView; 
bookView mBookView; 
Handler AniEndHandle; 
static boolean closeBook = false; 
 
private enum Corner { 
  LeftTop, 
  RightTop, 
  LeftBottom, 
  RightBottom, 
  None 
}; 
private Corner mSelectCorner; 
final int clickCornerLen = 250*250; //50dip 
float scrollX = 0,scrollY = 0; 
int indexPage = 0; 
 
public enum BookState { 
  ABOUT_TO_ANIMATE, 
  ANIMATING, 
  ANIMATE_END, 
  READY, 
  TRACKING 
}; 
private BookState mState; 
private Point aniStartPos; 
private Point aniStopPos; 
private Date aniStartTime; 
private long aniTime = 800; 
private long timeOffset = 10; 
 
Listener mListener; 
PageAdapter mPageAdapter; 
 
private GestureDetector mGestureDetector; 
private BookOnGestureListener mGestureListener; 
 
public eBook(Context context) { 
  super(context); 
  Init(context); 
} 
 
public eBook(Context context, AttributeSet attrs) { 
  super(context, attrs); 
  Init(context); 
} 
 
public eBook(Context context, AttributeSet attrs, int defStyle) { 
  super(context, attrs, defStyle); 
  Init(context); 
} 
 
public static interface Listener { 
  public void onPrevPage(); 
  public void onNextPage(); 
  public void onInit(); 
} 
 
public static interface PageAdapter{ 
  public View getView(int position); 
  public int getCount(); 
} 
public void setListener(Listener listener) { 
  Log.d(LOG_TAG,"setListener"); 
  mListener = listener; 
} 
public void setPageAdapter(PageAdapter pa){ 
  Log.d(LOG_TAG,"setPageAdapter"); 
  mPageAdapter = pa; 
} 
 
public void Init(Context context){ 
  totalPageNum = 0; 
  mContext = context; 
   
  mSelectCorner = Corner.None; 
   
  mGestureListener = new BookOnGestureListener(); 
  mGestureDetector = new GestureDetector(mGestureListener); 
  mGestureDetector.setIsLongpressEnabled(false); 
  AniEndHandle = new Handler(); 
   
  this.setOnTouchListener(touchListener); 
  this.setLongClickable(true); 
} 
 
public View getLeftPage(){ 
  return leftPage; 
} 
 
public View getRightPage(){ 
  return rightPage; 
} 
 
public View getPrevPage1(){ 
  return lrPage; 
} 
 
public View getPrevPage2(){ 
  return llPage; 
} 
 
public View getNextPage1(){ 
  return rlPage; 
} 
 
public View getNextPage2(){ 
  return rrPage; 
} 
 
public int getIndexForLeftPage(){ 
  return indexPage; 
} 
 
public int getIndexForRightPage(){ 
  return indexPage + 1; 
} 
 
public void setIndexForLeftPage(int index){ 
  if(index >= 0 && index < totalPageNum){ 
   if((index % 2) == 0) 
    indexPage = index; 
   else 
    indexPage = index - 1; 
  } 
} 
 
public void updatePageView(){ 
  Log.d(LOG_TAG,"updatePageView"); 
  if(indexPage < 0 || indexPage > totalPageNum - 1){ 
   Log.d(LOG_TAG,"indexPage exceed bound"); 
   return; 
  } 
  invisibleView.removeAllViews(); 
  mView.removeAllViews(); 
   
  leftPage = mPageAdapter.getView(indexPage); 
  if(leftPage == null)leftPage = new WhiteView(mContext); 
  leftPage.setLayoutParams(new LayoutParams(contentWidth/2,contentHeight)); 
  mView.addView(leftPage); 
   
  lrPage = mPageAdapter.getView(indexPage-1); 
  if(lrPage == null)lrPage = new WhiteView(mContext); 
  lrPage.setLayoutParams(new LayoutParams(contentWidth/2,contentHeight)); 
  invisibleView.addView(lrPage); 
   
  llPage = mPageAdapter.getView(indexPage-2); 
  if(llPage == null)llPage = new WhiteView(mContext); 
  llPage.setLayoutParams(new LayoutParams(contentWidth/2,contentHeight)); 
  invisibleView.addView(llPage); 
   
  rightPage = mPageAdapter.getView(indexPage+1); 
  if(rightPage == null)rightPage = new WhiteView(mContext); 
  rightPage.setLayoutParams(new LayoutParams(contentWidth/2,contentHeight)); 
  mView.addView(rightPage); 
   
  rlPage = mPageAdapter.getView(indexPage+2); 
  if(rlPage == null)rlPage = new WhiteView(mContext); 
  rlPage.setLayoutParams(new LayoutParams(contentWidth/2,contentHeight)); 
  invisibleView.addView(rlPage); 
   
  rrPage = mPageAdapter.getView(indexPage+3); 
  if(rrPage == null)rrPage = new WhiteView(mContext); 
  rrPage.setLayoutParams(new LayoutParams(contentWidth/2,contentHeight)); 
  invisibleView.addView(rrPage); 
   
  Log.d(LOG_TAG,"updatePageView finish"); 
} 
 
OnTouchListener touchListener = new OnTouchListener() { 
  public boolean onTouch(View v, MotionEvent event) { 
   Log.d(LOG_TAG, "onTouch " + " x: " + event.getX() + " y: " + event.getY() + 
     " mState:" + mState); 
   mGestureDetector.onTouchEvent(event); 
   int action = event.getAction(); 
   if (action == MotionEvent.ACTION_UP && mSelectCorner != Corner.None  
     && mState == BookState.TRACKING) { 
    if(mState == BookState.ANIMATING)return false; 
    if(mSelectCorner == Corner.LeftTop || mSelectCorner == Corner.RightTop){ 
     if(scrollX < contentWidth/2){ 
      aniStopPos = new Point(0,0); 
     }else{ 
      aniStopPos = new Point(contentWidth,0); 
     } 
    }else if(mSelectCorner == Corner.LeftBottom || mSelectCorner == Corner.RightBottom){ 
     if(scrollX < contentWidth/2){ 
      aniStopPos = new Point(0,contentHeight); 
     }else{ 
      aniStopPos = new Point(contentWidth,contentHeight); 
     } 
    } 
    aniStartPos = new Point((int)scrollX,(int)scrollY); 
    aniTime = 800; 
    mState = BookState.ABOUT_TO_ANIMATE; 
    closeBook = true; 
    aniStartTime = new Date(); 
    mBookView.startAnimation(); 
   } 
   return false; 
  } 
}; 
 
class BookOnGestureListener implements OnGestureListener { 
  public boolean onDown(MotionEvent event) { 
   Log.d(LOG_TAG, "onDown"); 
   if(mState == BookState.ANIMATING)return false; 
   float x = event.getX(), y = event.getY(); 
   int w = contentWidth, h = contentHeight; 
   if(x*x + y*y < clickCornerLen){ 
    if(indexPage > 1){ 
     mSelectCorner = Corner.LeftTop; 
     aniStartPos = new Point(0,0); 
    } 
   }else if((x-w)*(x-w)+ y*y < clickCornerLen){ 
    if(indexPage < totalPageNum-2){ 
     mSelectCorner = Corner.RightTop; 
     aniStartPos = new Point(contentWidth,0); 
    } 
   }else if(x*x + (y-h)*(y-h) < clickCornerLen){ 
    if(indexPage > 1){ 
     mSelectCorner = Corner.LeftBottom; 
     aniStartPos = new Point(0,contentHeight); 
    } 
   }else if((x-w)*(x-w) + (y-h)*(y-h) < clickCornerLen){ 
    if(indexPage < totalPageNum-2){ 
     mSelectCorner = Corner.RightBottom; 
     aniStartPos = new Point(contentWidth,contentHeight); 
    } 
   } 
   if(mSelectCorner != Corner.None){ 
    aniStopPos = new Point((int)x,(int)y); 
    aniTime = 800; 
    mState = BookState.ABOUT_TO_ANIMATE; 
    closeBook = false; 
    aniStartTime = new Date(); 
    mBookView.startAnimation(); 
   } 
   return false; 
  } 
   
  public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
   Log.d(LOG_TAG, "onFling velocityX:"+velocityX+" velocityY:"+velocityY); 
   if(mSelectCorner != Corner.None){ 
    if(mSelectCorner == Corner.LeftTop || mSelectCorner == Corner.RightTop){ 
     if(velocityX < 0){ 
      aniStopPos = new Point(0,0); 
     }else{ 
      aniStopPos = new Point(contentWidth,0); 
     } 
    }else if(mSelectCorner == Corner.LeftBottom || mSelectCorner == Corner.RightBottom){ 
     if(velocityX < 0){ 
      aniStopPos = new Point(0,contentHeight); 
     }else{ 
      aniStopPos = new Point(contentWidth,contentHeight); 
     } 
    } 
    Log.d(LOG_TAG, "onFling animate"); 
    aniStartPos = new Point((int)scrollX,(int)scrollY); 
    aniTime = 1000; 
    mState = BookState.ABOUT_TO_ANIMATE; 
    closeBook = true; 
    aniStartTime = new Date(); 
    mBookView.startAnimation(); 
   } 
   return false; 
  } 
 
  public void onLongPress(MotionEvent e) { 
   Log.d(LOG_TAG, "onLongPress"); 
  } 
 
  public boolean onScroll(MotionEvent e1, MotionEvent e2, 
    float distanceX, float distanceY) { 
//   if(mState == BookState.ANIMATING)return false; 
   mState = BookState.TRACKING; 
   if(mSelectCorner != Corner.None){ 
    scrollX = e2.getX(); 
    scrollY = e2.getY(); 
    mBookView.startAnimation(); 
   } 
   return false; 
  } 
 
  public void onShowPress(MotionEvent e) { 
   Log.d(LOG_TAG, "onShowPress"); 
  } 
 
  public boolean onSingleTapUp(MotionEvent e) { 
   Log.d(LOG_TAG, "onSingleTapUp"); 
   if(mSelectCorner != Corner.None){ 
    if(mSelectCorner == Corner.LeftTop || mSelectCorner == Corner.RightTop){ 
     if(scrollX < contentWidth/2){ 
      aniStopPos = new Point(0,0); 
     }else{ 
      aniStopPos = new Point(contentWidth,0); 
     } 
    }else if(mSelectCorner == Corner.LeftBottom || mSelectCorner == Corner.RightBottom){ 
     if(scrollX < contentWidth/2){ 
      aniStopPos = new Point(0,contentHeight); 
     }else{ 
      aniStopPos = new Point(contentWidth,contentHeight); 
     } 
    } 
    aniStartPos = new Point((int)scrollX,(int)scrollY); 
    aniTime = 800; 
    mState = BookState.ABOUT_TO_ANIMATE; 
    closeBook = true; 
    aniStartTime = new Date(); 
    mBookView.startAnimation(); 
   } 
   return false; 
  } 
} 
 
protected void onFinishInflate() { 
  Log.d(LOG_TAG, "onFinishInflate"); 
  super.onFinishInflate(); 
} 
 
protected void onLayout(boolean changed, int l, int t, int r, int b) { 
  super.onLayout(changed, l, t, r, b); 
   
  contentWidth = this.getWidth(); 
  contentHeight = this.getHeight(); 
  if(contentWidth == 0) contentWidth = defaultWidth; 
  if(contentHeight == 0) contentHeight = defaultHeight; 
  Log.d(LOG_TAG, "onLayout, width:" + contentWidth + " height:" + contentHeight); 
} 
 
protected void dispatchDraw(Canvas canvas) { 
  Log.d(LOG_TAG, "dispatchDraw"); 
  super.dispatchDraw(canvas); 
  if(!hasInit){ 
   hasInit = true; 
   indexPage = 0; 
   if(mPageAdapter == null){ 
    throw new RuntimeException("please set the PageAdapter on init"); 
   } 
   totalPageNum = mPageAdapter.getCount(); 
   mView = new LinearLayout(mContext); 
   mView.setLayoutParams(new LayoutParams(contentWidth,contentHeight)); 
   mView.setBackgroundColor(0xffffffff); 
   mState = BookState.READY; 
    
   invisibleView = new LinearLayout(mContext); 
   invisibleView.setLayoutParams(new LayoutParams(contentWidth,contentHeight)); 
    
   mMidView = new MidView(mContext); 
   mMidView.setLayoutParams(new LayoutParams(contentWidth,contentHeight)); 
    
   this.addView(invisibleView); 
   this.addView(mView); 
   this.addView(mMidView); 
    
   mBookView = new bookView(mContext); 
   mBookView.setLayoutParams(new LayoutParams(contentWidth,contentHeight)); 
   this.addView(mBookView); 
    
//   invisibleView.setVisibility(INVISIBLE); 
//   mBookView.setVisibility(GONE); 
   updatePageView(); 
   invalidate(); 
   if(mListener != null)mListener.onInit(); 
  }else if (mState == BookState.READY){ 
   mBookView.update(); 
  } 
} 
 
class bookView extends SurfaceView implements SurfaceHolder.Callback{ 
  DrawThread dt; //后台屏幕绘制线程 
  SurfaceHolder surfaceHolder; 
  Paint mDarkPaint = new Paint(); 
  Paint mPaint = new Paint(); 
  Bitmap tmpBmp = Bitmap.createBitmap(contentWidth/2,contentHeight,Bitmap.Config.ARGB_8888); 
  Canvas mCanvas = new Canvas(tmpBmp); 
   
  Paint bmpPaint = new Paint(); 
  Paint ivisiblePaint = new Paint(); 
   
  public bookView(Context context) { 
   super(context); 
   surfaceHolder = getHolder(); 
   surfaceHolder.addCallback(this); 
    
   mDarkPaint.setColor(0x88000000); 
   Shader mLinearGradient = new LinearGradient(0, 0, contentWidth, 0, 
     new int[] { 0x00000000, 0x33000000,0x00000000 }, 
     new float[] { 0.35f, 0.5f, 0.65f }, 
     Shader.TileMode.MIRROR); 
   mPaint.setAntiAlias(true); 
   mPaint.setShader(mLinearGradient); 
    
   bmpPaint.setFilterBitmap(true); 
   bmpPaint.setAntiAlias(true); 
    
   ivisiblePaint.setAlpha(0); 
   ivisiblePaint.setFilterBitmap(true); 
   ivisiblePaint.setAntiAlias(true); 
   ivisiblePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 
  } 
  public void startAnimation(){ 
//   update(); 
   if(dt == null){ 
    Log.d(LOG_TAG,"startAnimation"); 
//    mBookView.setVisibility(VISIBLE); 
    dt = new DrawThread(this,getHolder()); 
    dt.start(); 
   } 
  } 
   
  public void stopAnimation(){ 
   Log.d(LOG_TAG,"stopAnimation"); 
//   AniEndHandle.post(new Runnable(){ 
//    public void run() { 
//     mBookView.setVisibility(GONE); 
//    } 
//   }); 
   if(dt != null){ 
    dt.flag = false; 
    Thread t = dt; 
    dt = null; 
    t.interrupt(); 
   } 
  } 
 
  public void drawLT(Canvas canvas){ 
   double dx = scrollX - contentWidth/2, dy = scrollY; 
   double len = Math.sqrt(dx*dx + dy*dy); 
   if(len > contentWidth/2){ 
    scrollX = (float) (contentWidth*dx/(2.0*len)) + contentWidth/2; 
    scrollY = (float) (contentWidth*dy/(2.0*len)); 
   } 
   dy = contentHeight - scrollY; 
   len = Math.sqrt(dx*dx + dy*dy); 
   double d = Math.sqrt(contentWidth*contentWidth/4 + contentHeight*contentHeight); 
   if(len > d){ 
    scrollX = (float) (d*dx/len) + contentWidth/2; 
    scrollY = contentHeight - (float) (d*dy/len); 
   } 
   double px = scrollX; 
   double py = scrollY; 
   double arc = 2 * Math.atan(py/px)*180/Math.PI; 
 
   Matrix m = new Matrix(); 
   m.postTranslate(scrollX - contentWidth/2, scrollY); 
   m.postRotate((float)(arc),scrollX,scrollY); 
 
   lrPage.draw(mCanvas); 
 
   Paint ps = new Paint(); 
   Shader lg1 = new LinearGradient(contentWidth/2, 0, 
      contentWidth/2 - (float)px,(float)py, 
      new int[] { 0x00000000, 0x33000000,0x00000000 }, 
      new float[] { 0.35f, 0.5f, 0.65f }, 
      Shader.TileMode.CLAMP); 
   ps.setShader(lg1); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
   canvas.drawBitmap(tmpBmp, m, bmpPaint); 
 
   llPage.draw(mCanvas); 
   Shader lg2 = new LinearGradient(scrollX,scrollY,0, 0, 
     new int[] { 0x00000000, 0x33000000,0x00000000 }, 
     new float[] { 0.35f, 0.5f, 0.65f }, 
     Shader.TileMode.CLAMP); 
   ps.setShader(lg2); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
 
   arc = arc*Math.PI/360; 
   Path path = new Path(); 
   double r = Math.sqrt(px * px + py * py); 
   double p1 = r/(2*Math.cos(arc)); 
   double p2 = r/(2*Math.sin(arc)); 
   Log.d(LOG_TAG,"p1: " + p1 + " p2:" + p2); 
   if(arc == 0){ 
    path.moveTo((float)p1, 0); 
    path.lineTo(contentWidth/2, 0); 
    path.lineTo(contentWidth/2, contentHeight); 
    path.lineTo((float)p1, contentHeight); 
    path.close(); 
   }else if(p2 > contentHeight || p2 < 0){ 
    double p3 = (p2 - contentHeight)*Math.tan(arc); 
    path.moveTo((float)p1, 0); 
    path.lineTo(contentWidth/2, 0); 
    path.lineTo(contentWidth/2, contentHeight); 
    path.lineTo((float)p3, contentHeight); 
    path.close(); 
   }else{ 
    path.moveTo((float)p1, 0); 
    path.lineTo(contentWidth/2, 0); 
    path.lineTo(contentWidth/2, contentHeight); 
    path.lineTo(0, contentHeight); 
    path.lineTo(0, (float)p2); 
    path.close(); 
   } 
   mCanvas.drawPath(path, ivisiblePaint); 
   canvas.drawBitmap(tmpBmp, 0, 0, null); 
  } 
 
  public void drawLB(Canvas canvas){ 
   double dx = scrollX - contentWidth/2, dy = scrollY - contentHeight; 
   double len = Math.sqrt(dx*dx + dy*dy); 
   if(len > contentWidth/2){ 
    scrollX = (float) (contentWidth*dx/(2.0*len)) + contentWidth/2; 
    scrollY = (float) (contentWidth*dy/(2.0*len)) + contentHeight; 
   } 
   dy = scrollY; 
   len = Math.sqrt(dx*dx + dy*dy); 
   double d = Math.sqrt(contentWidth*contentWidth/4 + contentHeight*contentHeight); 
   if(len > d){ 
    scrollX = (float) (d*dx/len) + contentWidth/2; 
    scrollY = (float) (d*dy/len); 
   } 
   double px = scrollX; 
   double py = contentHeight - scrollY; 
   double arc = 2 * Math.atan(py/px)*180/Math.PI; 
    
   Matrix m = new Matrix(); 
   m.postTranslate(scrollX - contentWidth/2, scrollY - contentHeight); 
   m.postRotate((float)(-arc),scrollX,scrollY); 
    
   lrPage.draw(mCanvas); 
    
   Paint ps = new Paint(); 
   Shader lg1 = new LinearGradient(contentWidth/2, contentHeight, 
      contentWidth/2 - (float)px, contentHeight - (float)py, 
      new int[] { 0x00000000, 0x33000000,0x00000000 }, 
      new float[] { 0.35f, 0.5f, 0.65f }, 
      Shader.TileMode.CLAMP); 
   ps.setShader(lg1); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
   canvas.drawBitmap(tmpBmp, m, bmpPaint); 
    
   llPage.draw(mCanvas); 
   Shader lg2 = new LinearGradient(scrollX,scrollY,0, contentHeight, 
     new int[] { 0x00000000, 0x33000000,0x00000000 }, 
     new float[] { 0.35f, 0.5f, 0.65f }, 
     Shader.TileMode.CLAMP); 
   ps.setShader(lg2); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
    
   arc = arc*Math.PI/360; 
   Path path = new Path(); 
   double r = Math.sqrt(px * px + py * py); 
   double p1 = r/(2*Math.cos(arc)); 
   double p2 = r/(2*Math.sin(arc)); 
   Log.d(LOG_TAG,"p1: " + p1 + " p2:" + p2); 
   if(arc == 0){ 
    path.moveTo((float)p1, 0); 
    path.lineTo(contentWidth/2, 0); 
    path.lineTo(contentWidth/2, contentHeight); 
    path.lineTo((float)p1, contentHeight); 
    path.close(); 
   }else if(p2 > contentHeight || p2 < 0){ 
    double p3 = (p2 - contentHeight)*Math.tan(arc); 
    path.moveTo((float)p3, 0); 
    path.lineTo(contentWidth/2, 0); 
    path.lineTo(contentWidth/2, contentHeight); 
    path.lineTo((float)p1, contentHeight); 
    path.close(); 
   }else{ 
    path.moveTo(0, 0); 
    path.lineTo(contentWidth/2, 0); 
    path.lineTo(contentWidth/2, contentHeight); 
    path.lineTo((float)p1, contentHeight); 
    path.lineTo(0, contentHeight - (float)p2); 
    path.close(); 
   } 
   mCanvas.drawPath(path, ivisiblePaint); 
   canvas.drawBitmap(tmpBmp, 0, 0, null); 
  } 
   
  public void drawRT(Canvas canvas){ 
   double dx = scrollX - contentWidth/2, dy = scrollY; 
   double len = Math.sqrt(dx*dx + dy*dy); 
   if(len > contentWidth/2){ 
    scrollX = (float) (contentWidth*dx/(2.0*len)) + contentWidth/2; 
    scrollY = (float) (contentWidth*dy/(2.0*len)); 
   } 
   dy = contentHeight - scrollY; 
   len = Math.sqrt(dx*dx + dy*dy); 
   double d = Math.sqrt(contentWidth*contentWidth/4 + contentHeight*contentHeight); 
   if(len > d){ 
    scrollX = (float) (d*dx/len) + contentWidth/2; 
    scrollY = contentHeight - (float) (d*dy/len); 
   } 
   double px = contentWidth - scrollX; 
   double py = scrollY; 
   double arc = 2 * Math.atan(py/px)*180/Math.PI; 
    
   Matrix m = new Matrix(); 
   m.postTranslate(scrollX, scrollY); 
   m.postRotate((float)(-arc),scrollX,scrollY); 
    
   rlPage.draw(mCanvas); 
    
   Paint ps = new Paint(); 
   Shader lg1 = new LinearGradient(0, 0, (float)px, (float)py, 
      new int[] { 0x00000000, 0x33000000,0x00000000 }, 
      new float[] { 0.35f, 0.5f, 0.65f }, 
      Shader.TileMode.CLAMP); 
   ps.setShader(lg1); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
   canvas.drawBitmap(tmpBmp, m, bmpPaint); 
    
   rrPage.draw(mCanvas); 
   Shader lg2 = new LinearGradient(scrollX-contentWidth/2, scrollY, 
     contentWidth/2, 0, 
     new int[] { 0x00000000, 0x33000000,0x00000000 }, 
     new float[] { 0.35f, 0.5f, 0.65f }, 
     Shader.TileMode.CLAMP); 
   ps.setShader(lg2); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
    
   arc = arc*Math.PI/360; 
   Path path = new Path(); 
   double r = Math.sqrt(px * px + py * py); 
   double p1 = contentWidth/2 - r/(2*Math.cos(arc)); 
   double p2 = r/(2*Math.sin(arc)); 
   Log.d(LOG_TAG,"p1: " + p1 + " p2:" + p2); 
   if(arc == 0){ 
    path.moveTo(0, 0); 
    path.lineTo((float)p1, 0); 
    path.lineTo((float)p1, contentHeight); 
    path.lineTo(0, contentHeight); 
    path.close(); 
   }else if(p2 > contentHeight || p2 < 0){ 
    double p3 = contentWidth/2 - (p2 - contentHeight)*Math.tan(arc); 
    path.moveTo(0, 0); 
    path.lineTo((float)p1, 0); 
    path.lineTo((float)p3, contentHeight); 
    path.lineTo(0, contentHeight); 
    path.close(); 
   }else{ 
    path.moveTo(0, 0); 
    path.lineTo((float)p1, 0); 
    path.lineTo(contentWidth/2, (float)p2); 
    path.lineTo(contentWidth/2, contentHeight); 
    path.lineTo(0, contentHeight); 
    path.close(); 
   } 
   mCanvas.drawPath(path, ivisiblePaint); 
   canvas.drawBitmap(tmpBmp, contentWidth/2, 0, null); 
  } 
   
  public void drawRB(Canvas canvas){ 
   double dx = scrollX - contentWidth/2, dy = contentHeight - scrollY; 
   double len = Math.sqrt(dx*dx + dy*dy); 
   if(len > contentWidth/2){ 
    scrollX = (float) (contentWidth*dx/(2.0*len)) + contentWidth/2; 
    scrollY = contentHeight - (float) (contentWidth*dy/(2.0*len)); 
   } 
   dy = scrollY; 
   len = Math.sqrt(dx*dx + dy*dy); 
   double d = Math.sqrt(contentWidth*contentWidth/4 + contentHeight*contentHeight); 
   if(len > d){ 
    scrollX = (float) (d*dx/len) + contentWidth/2; 
    scrollY = (float) (d*dy/len); 
   } 
   double px = contentWidth - scrollX; 
   double py = contentHeight - scrollY; 
   double arc = 2 * Math.atan(py/px)*180/Math.PI; 
    
   Matrix m = new Matrix(); 
   m.postTranslate(scrollX, scrollY - contentHeight); 
   m.postRotate((float)(arc),scrollX,scrollY); 
    
   rlPage.draw(mCanvas); 
    
   Paint ps = new Paint(); 
   Shader lg1 = new LinearGradient(0, contentHeight, 
      (float)px,contentHeight-(float)py, 
      new int[] { 0x00000000, 0x33000000,0x00000000 }, 
      new float[] { 0.35f, 0.5f, 0.65f }, 
      Shader.TileMode.CLAMP); 
   ps.setShader(lg1); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
   canvas.drawBitmap(tmpBmp, m, bmpPaint); 
    
   rrPage.draw(mCanvas); 
   Shader lg2 = new LinearGradient(scrollX-contentWidth/2, scrollY, 
     contentWidth/2, contentHeight, 
     new int[] { 0x00000000, 0x33000000,0x00000000 }, 
     new float[] { 0.35f, 0.5f, 0.65f }, 
     Shader.TileMode.CLAMP); 
   ps.setShader(lg2); 
   mCanvas.drawRect(0, 0, contentWidth/2, contentHeight, ps); 
    
   arc = arc*Math.PI/360; 
   Path path = new Path(); 
   double r = Math.sqrt(px * px + py * py); 
   double p1 = contentWidth/2 - r/(2*Math.cos(arc)); 
   double p2 = r/(2*Math.sin(arc)); 
   Log.d(LOG_TAG,"p1: " + p1 + " p2:" + p2); 
   if(arc == 0){ 
    path.moveTo(0, 0); 
    path.lineTo((float)p1, 0); 
    path.lineTo((float)p1, contentHeight); 
    path.lineTo(0, contentHeight); 
    path.close(); 
   }else if(p2 > contentHeight || p2 < 0){ 
    double p3 = contentWidth/2 - (p2 - contentHeight)*Math.tan(arc); 
    path.moveTo(0, 0); 
    path.lineTo((float)p3, 0); 
    path.lineTo((float)p1, contentHeight); 
    path.lineTo(0, contentHeight); 
    path.close(); 
   }else{ 
    path.moveTo(0, 0); 
    path.lineTo(contentWidth/2, 0); 
    path.lineTo(contentWidth/2, contentHeight - (float)p2); 
    path.lineTo((float)p1, contentHeight); 
    path.lineTo(0, contentHeight); 
    path.close(); 
   } 
   mCanvas.drawPath(path, ivisiblePaint); 
   canvas.drawBitmap(tmpBmp, contentWidth/2, 0, null); 
  } 
   
  public void drawPrevPageEnd(Canvas canvas){ 
   llPage.draw(mCanvas); 
   canvas.drawBitmap(tmpBmp, 0, 0, null); 
   lrPage.draw(mCanvas); 
   canvas.drawBitmap(tmpBmp, contentWidth/2, 0, null); 
    
   canvas.drawRect(0, 0, contentWidth, contentHeight, mPaint); 
   canvas.drawLine(contentWidth/2, 0, contentWidth/2, contentHeight, mDarkPaint); 
  } 
   
  public void drawNextPageEnd(Canvas canvas) { 
   rlPage.draw(mCanvas); 
   canvas.drawBitmap(tmpBmp, 0, 0, null); 
   rrPage.draw(mCanvas); 
   canvas.drawBitmap(tmpBmp, contentWidth / 2, 0, null); 
 
   canvas.drawRect(0, 0, contentWidth, contentHeight, mPaint); 
   canvas.drawLine(contentWidth/2, 0, contentWidth/2, contentHeight, mDarkPaint); 
  } 
   
  public void drawPage(Canvas canvas){ 
   if(mSelectCorner == Corner.LeftTop){ 
    Log.d(LOG_TAG,"click left top"); 
    drawLT(canvas); 
   }else if(mSelectCorner == Corner.LeftBottom){ 
    Log.d(LOG_TAG,"click left bottom"); 
    drawLB(canvas); 
   }else if(mSelectCorner == Corner.RightTop){ 
    Log.d(LOG_TAG,"click right top"); 
    drawRT(canvas); 
   }else if(mSelectCorner == Corner.RightBottom){ 
    Log.d(LOG_TAG,"click right bottom"); 
    drawRB(canvas); 
   } 
  } 
   
  public void update(){ 
   Canvas canvas = surfaceHolder.lockCanvas(null);//获取BallView的画布 
   try{ 
    synchronized(surfaceHolder){ 
     doDraw(canvas);  //调用BallView的doDraw方法进行绘制 
    } 
   } 
   catch(Exception e){ 
    e.printStackTrace();   //捕获并打印异常 
   } 
   finally{ 
    if(canvas != null){  //如果canvas不为空 
     surfaceHolder.unlockCanvasAndPost(canvas);//surfaceHolder解锁并将画布对象传回 
    } 
   } 
  } 
   
  protected void doDraw(Canvas canvas) { 
   Log.d(LOG_TAG, "bookView doDraw"); 
//   super.onDraw(canvas); 
   mView.draw(canvas); 
    
   canvas.drawRect(0, 0, contentWidth, contentHeight, mPaint); 
   canvas.drawLine(contentWidth/2, 0, contentWidth/2, contentHeight, mDarkPaint); 
  } 
 
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
    
  } 
 
  public void surfaceCreated(SurfaceHolder holder) { 
   update(); 
  } 
 
  public void surfaceDestroyed(SurfaceHolder holder) { 
   if(dt != null){ 
    dt.flag = false; //停止线程的执行 
    dt = null;   //将dt指向的对象声明为垃圾 
   } 
  } 
} 
 
public boolean getAnimateData(){ 
  long time = aniTime; 
  Date date = new Date(); 
  long t = date.getTime()-aniStartTime.getTime(); 
  t += timeOffset; 
  if(t < 0 || t > time){ 
   mState = BookState.ANIMATE_END; 
   return false; 
  }else{ 
   mState = BookState.ANIMATING; 
   double sx = aniStopPos.x - aniStartPos.x; 
   double gx = 2*sx/(time*time); 
   scrollX = (float) (gx*time*t - gx*t*t/2 + aniStartPos.x); 
   double sy = aniStopPos.y - aniStartPos.y; 
   double gy = 2*sy/(time*time); 
   scrollY = (float) (gy*time*t - gy*t*t/2 + aniStartPos.y); 
   return true; 
  } 
} 
 
public void handleAniEnd(Canvas canvas){ 
  if(closeBook){ 
   closeBook = false; 
   if(mSelectCorner == Corner.LeftTop || mSelectCorner == Corner.LeftBottom){ 
    if(scrollX > contentWidth/2){ 
     Log.d(LOG_TAG,"handleAniEnd -2,indexPage:"+ (indexPage-2)); 
     indexPage -= 2; 
     mBookView.drawPrevPageEnd(canvas); 
     AniEndHandle.post(new Runnable(){ 
      public void run() { 
       updatePageView(); 
       if(mListener != null){ 
        Log.d(LOG_TAG,"onPrevPage"); 
        mListener.onPrevPage(); 
       } 
      } 
     }); 
    }else{ 
     mBookView.doDraw(canvas); 
    } 
   }else if(mSelectCorner == Corner.RightTop || mSelectCorner == Corner.RightBottom){ 
    if(scrollX < contentWidth/2){ 
     Log.d(LOG_TAG,"handleAniEnd +2,indexPage:"+ (indexPage+2)); 
     indexPage += 2; 
     mBookView.drawNextPageEnd(canvas); 
     AniEndHandle.post(new Runnable(){ 
      public void run() { 
       updatePageView(); 
       if(mListener != null){ 
        Log.d(LOG_TAG,"onNextPage"); 
        mListener.onNextPage(); 
       } 
      } 
     }); 
    }else{ 
     mBookView.doDraw(canvas); 
    } 
   } 
   mSelectCorner = Corner.None; 
   mState = BookState.READY; 
  }else{ 
   mState = BookState.TRACKING; 
  } 
  mBookView.stopAnimation(); 
  AniEndHandle.post(new Runnable(){ 
   public void run() { 
    eBook.this.invalidate(); 
   } 
  }); 
} 
 
class WhiteView extends View{ 
  public WhiteView(Context context) { 
   super(context); 
  } 
   
  protected void onDraw(Canvas canvas) { 
   super.onDraw(canvas); 
   canvas.drawColor(Color.WHITE); 
  } 
} 
 
class MidView extends View{ 
  public MidView(Context context) { 
   super(context); 
  } 
   
  protected void onDraw(Canvas canvas) { 
   super.onDraw(canvas); 
   Paint mPaint = new Paint(); 
   Shader mLinearGradient = new LinearGradient(0, 0, contentWidth, 0, 
      new int[] { 0x00000000, 0x33000000,0x00000000 }, 
      new float[] { 0.35f, 0.5f, 0.65f }, 
      Shader.TileMode.MIRROR); 
   mPaint.setAntiAlias(true); 
   mPaint.setShader(mLinearGradient); 
   canvas.drawRect(0, 0, contentWidth, contentHeight, mPaint); 
    
   Paint mDarkPaint = new Paint(); 
   mDarkPaint.setColor(0x88000000); 
   canvas.drawLine(contentWidth/2, 0, contentWidth/2, contentHeight, mDarkPaint); 
  } 
} 
 
public class DrawThread extends Thread{ 
  bookView bv;    //bookView对象引用 
  SurfaceHolder surfaceHolder;//SurfaceHolder对象引用 
  boolean flag=false;   //线程执行标志位 
  int sleepSpan = 30;   //休眠时间 
  public DrawThread(bookView bv,SurfaceHolder surfaceHolder){ 
   this.bv = bv;  //为BallView对象应用赋值 
   this.surfaceHolder = surfaceHolder; //为SurfaceHolder对象应用赋值 
   this.flag = true;  //设置标志位 
  } 
   
  public void run(){ 
   Canvas canvas = null;//声明一个Canvas对象 
   while(flag){ 
    try{ 
     canvas = surfaceHolder.lockCanvas(null);//获取BallView的画布 
     if(canvas == null)continue; 
     synchronized(surfaceHolder){ 
      if(mState == BookState.ABOUT_TO_ANIMATE || mState == BookState.ANIMATING){ 
       bv.doDraw(canvas);  //调用BallView的doDraw方法进行绘制 
       getAnimateData(); 
       bv.drawPage(canvas); 
      }else if(mState == BookState.TRACKING){ 
       bv.doDraw(canvas); 
       bv.drawPage(canvas); 
      }else if(mState == BookState.ANIMATE_END){ 
       handleAniEnd(canvas); 
      } 
     } 
    } 
    catch(Exception e){ 
     e.printStackTrace();   //捕获并打印异常 
    } 
    finally{ 
     if(canvas != null){  //如果canvas不为空 
      surfaceHolder.unlockCanvasAndPost(canvas);//surfaceHolder解锁并将画布对象传回 
     } 
    } 
    try{ 
     Thread.sleep(sleepSpan);  //线程休眠一段时间 
    } 
    catch(Exception e){ 
     e.printStackTrace();  //捕获并打印异常 
    } 
   } 
  } 
} 
} |   
 
 
 
 |