zoukankan      html  css  js  c++  java
  • Android实现翻页功能原理

    第一种翻页效果如下:

    实现原理:

    当前手指触摸点为a,则 a点坐标为(ax,ay), 由三角形acb与三角形cmb为对称三角形并且直线cp为am垂直平分线,则 B点坐标为(ax/2,ay/2)。

    作gf垂直于om且cb垂直于am, 三角形cfg与gfm相似,则 cf:gf = gf:mf      cf=(gf * gf) / mf     gf长度为g点纵坐标     mf长度为g点横坐标   

    cf长度可求    c点坐标可求 由c点、g点可确定过两点间的直线, 当该直线中x=0时求出与y足交点。

    第二种翻页效果

    实现原理:

    使用贝赛尔曲线。曲线有四个点:起始点、终止点(也称锚点)以及两个相互分离的中间点。滑动两个中间点,贝塞尔曲线的形状会发生变化。

    根据第一种翻页效果原理可以确定a、e、h、f、g ,由eh平行于cj且af垂直于eh,则 af垂直于cj则三角形egf相似于三角形cnf 则有ef:cf = gf:nf 。

    设n为ag中点 则有cf=(3/2)*ef ,则c点坐标可求 由c点、k点坐标已知可知过两点间的直线

    由该直线可计算与y轴相交点j 由a、e、c、j可计算两条直线的相交点b 同理可求点k。

    在Android中的具体实现步骤:

    起始页展示

    1.创建屏幕尺寸的bmp 2.将图片转化为canvas 3.获取起始页面数据 3.在canvas中绘制起始页数据 4.在当前视图中复写onDraw进行重绘出bmp对象

    翻页处理

    1.初始化时创建两个bmp(bmp1、bmp2)并将其转换为canvas(canvas1、canvas2)

    2.获取手势首次触摸的区域 (例:当首次点击屏幕的位置x<50&&y<50则为左上角)

    3.根据首次点击区域判断需要展示的数据(例:首次点击处于左侧区域【左上、左下】的则判断操作为下一页操作)

    4.获取下一页中数据并绘制出来在canvas2中

    5.根据1中获取的区域位置调用起始动画使视图移动到手势首次点击位置

    6.获取手势每次移动的坐标并根据移动坐标计算绘制的各个点的坐标

    7.每次移动刷新视图

    源码示例下载1

    源码示例下载2

    源码实例1:

    项目结构:

    PageWidget:

    package sf.hmg.turntest;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.PointF;
    import android.graphics.Region;
    import android.graphics.drawable.GradientDrawable;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;

    public class PageWidget extends View {
    private static final String TAG = "hmg";
    private int mWidth = 480;
    private int mHeight = 800;
    private int mCornerX = 0; // 拖拽点对应的页脚
    private int mCornerY = 0;
    private Path mPath0;
    private Path mPath1;

    Bitmap mCurPageBitmap = null; //当前页
    Bitmap mCurPageBackBitmap = null;
    Bitmap mNextPageBitmap = null;

    PointF mTouch = new PointF(); // 拖拽点
    PointF mBezierStart1 = new PointF(); // 贝塞尔曲线起始点
    PointF mBezierControl1 = new PointF(); // 贝塞尔曲线控制点
    PointF mBeziervertex1 = new PointF(); // 贝塞尔曲线顶点
    PointF mBezierEnd1 = new PointF(); // 贝塞尔曲线结束点

    PointF mBezierStart2 = new PointF(); // 另一条贝塞尔曲线
    PointF mBezierControl2 = new PointF();
    PointF mBeziervertex2 = new PointF();
    PointF mBezierEnd2 = new PointF();

    float mMiddleX;
    float mMiddleY;
    float mDegrees;
    float mTouchToCornerDis;

    boolean mIsRTandLB; // 是否属于右上左下
    // for test
    float mMaxLength = (float) Math.hypot(480, 800);
    int[] mBackShadowColors;
    int[] mFrontShadowColors;
    GradientDrawable mBackShadowDrawableLR;
    GradientDrawable mBackShadowDrawableRL;
    GradientDrawable mFolderShadowDrawableLR;
    GradientDrawable mFolderShadowDrawableRL;

    GradientDrawable mFrontShadowDrawableHBT;
    GradientDrawable mFrontShadowDrawableHTB;
    GradientDrawable mFrontShadowDrawableVLR;
    GradientDrawable mFrontShadowDrawableVRL;

    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Paint mBitmapPaint;
    Paint paint;

    public PageWidget(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
    mPath0 = new Path();
    mPath1 = new Path();

    createDrawable();

    // ---------------------------------------
    mBitmap = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);
    mBitmapPaint = new Paint(Paint.DITHER_FLAG);

    mCurPageBitmap = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(mCurPageBitmap);
    paint = new Paint();
    canvas.drawColor(Color.YELLOW);
    canvas.drawBitmap(mCurPageBitmap, 0, 0, paint);

    mNextPageBitmap = Bitmap
    .createBitmap(480, 800, Bitmap.Config.ARGB_8888);
    canvas = new Canvas(mNextPageBitmap);
    canvas.drawColor(Color.GREEN);
    canvas.drawBitmap(mNextPageBitmap, 0, 0, paint);
    }



    /**
    * Author : hmg25
    * Version: 1.0
    * Description : 计算拖拽点对应的拖拽脚
    */
    private void calcCornerXY(float x, float y) {
    if (x <= mWidth / 2)
    mCornerX = 0;
    else
    mCornerX = mWidth;
    if (y <= mHeight / 2)
    mCornerY = 0;
    else
    mCornerY = mHeight;
    if ((mCornerX == 0 && mCornerY == mHeight)
    || (mCornerX == mWidth && mCornerY == 0))
    mIsRTandLB = true;
    else
    mIsRTandLB = false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    if (event.getAction() == MotionEvent.ACTION_MOVE) {
    mCanvas.drawColor(0xFFAAAAAA);
    mTouch.x = event.getX();
    mTouch.y = event.getY();
    this.postInvalidate();
    }
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
    mCanvas.drawColor(0xFFAAAAAA);
    mTouch.x = event.getX();
    mTouch.y = event.getY();
    calcCornerXY(mTouch.x, mTouch.y);
    this.postInvalidate();
    }
    if (event.getAction() == MotionEvent.ACTION_UP) {
    mCanvas.drawColor(0xFFAAAAAA);
    mTouch.x = mCornerX;
    mTouch.y = mCornerY;
    this.postInvalidate();
    }
    // return super.onTouchEvent(event);
    return true;
    }


    /**
    * Author : Administrator
    * Version: 1.0
    * Description : 求解直线P1P2和直线P3P4的交点坐标
    */
    public PointF getCross(PointF P1, PointF P2, PointF P3, PointF P4) {
    PointF CrossP = new PointF();
    // 二元函数通式: y=ax+b
    float a1 = (P2.y - P1.y) / (P2.x - P1.x);
    float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x);

    float a2 = (P4.y - P3.y) / (P4.x - P3.x);
    float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x);
    CrossP.x = (b2 - b1) / (a1 - a2);
    CrossP.y = a1 * CrossP.x + b1;
    return CrossP;
    }

    private void calcPoints() {

    mMiddleX = (mTouch.x + mCornerX) / 2;
    mMiddleY = (mTouch.y + mCornerY) / 2;

    mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)
    * (mCornerY - mMiddleY) / (mCornerX - mMiddleX);
    mBezierControl1.y = mCornerY;
    mBezierControl2.x = mCornerX;
    mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)
    * (mCornerX - mMiddleX) / (mCornerY - mMiddleY);

    Log.i("hmg", "mTouchX " + mTouch.x + " mTouchY " + mTouch.y);
    Log.i("hmg", "mBezierControl1.x " + mBezierControl1.x
    + " mBezierControl1.y " + mBezierControl1.y);
    Log.i("hmg", "mBezierControl2.x " + mBezierControl2.x
    + " mBezierControl2.y " + mBezierControl2.y);

    mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x)
    / 2;
    mBezierStart1.y = mCornerY;

    mBezierStart2.x = mCornerX;
    mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y)
    / 2;

    Log.i("hmg", "mBezierStart1.x " + mBezierStart1.x
    + " mBezierStart1.y " + mBezierStart1.y);
    Log.i("hmg", "mBezierStart2.x " + mBezierStart2.x
    + " mBezierStart2.y " + mBezierStart2.y);

    mTouchToCornerDis = (float) Math.hypot((mTouch.x - mCornerX),
    (mTouch.y - mCornerY));

    mBezierEnd1 = getCross(mTouch, mBezierControl1, mBezierStart1,
    mBezierStart2);
    mBezierEnd2 = getCross(mTouch, mBezierControl2, mBezierStart1,
    mBezierStart2);

    Log.i("hmg", "mBezierEnd1.x " + mBezierEnd1.x + " mBezierEnd1.y "
    + mBezierEnd1.y);
    Log.i("hmg", "mBezierEnd2.x " + mBezierEnd2.x + " mBezierEnd2.y "
    + mBezierEnd2.y);

    /*
    * mBeziervertex1.x 推导
    * ((mBezierStart1.x+mBezierEnd1.x)/2+mBezierControl1.x)/2 化简等价于
    * (mBezierStart1.x+ 2*mBezierControl1.x+mBezierEnd1.x) / 4
    */
    mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4;
    mBeziervertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4;
    mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4;
    mBeziervertex2.y = (2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4;

    Log.i("hmg", "mBeziervertex1.x " + mBeziervertex1.x
    + " mBeziervertex1.y " + mBeziervertex1.y);
    Log.i("hmg", "mBeziervertex2.x " + mBeziervertex2.x
    + " mBeziervertex2.y " + mBeziervertex2.y);

    }

    private void drawCurrentPageArea(Canvas canvas, Bitmap bitmap, Path path) {
    mPath0.reset();
    mPath0.moveTo(mBezierStart1.x, mBezierStart1.y);
    mPath0.quadTo(mBezierControl1.x, mBezierControl1.y, mBezierEnd1.x,
    mBezierEnd1.y);
    mPath0.lineTo(mTouch.x, mTouch.y);
    mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y);
    mPath0.quadTo(mBezierControl2.x, mBezierControl2.y, mBezierStart2.x,
    mBezierStart2.y);
    mPath0.lineTo(mCornerX, mCornerY);
    mPath0.close();

    canvas.save();
    canvas.clipPath(path, Region.Op.XOR);
    canvas.drawBitmap(bitmap, 0, 0, null);
    canvas.restore();
    }

    private void drawNextPageAreaAndShadow(Canvas canvas, Bitmap bitmap) {
    mPath1.reset();
    mPath1.moveTo(mBezierStart1.x, mBezierStart1.y);
    mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y);
    mPath1.lineTo(mBeziervertex2.x, mBeziervertex2.y);
    mPath1.lineTo(mBezierStart2.x, mBezierStart2.y);
    mPath1.lineTo(mCornerX, mCornerY);
    mPath1.close();

    mDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl1.x
    - mCornerX, mBezierControl2.y - mCornerY));
    float f5 = mTouchToCornerDis /4;
    int leftx;
    int rightx;
    GradientDrawable mBackShadowDrawable;
    if(mIsRTandLB)
    {
    leftx=(int)(mBezierStart1.x - 1);
    rightx= (int)(mBezierStart1.x +mTouchToCornerDis /4+ 1);
    mBackShadowDrawable=mBackShadowDrawableLR;
    }else
    {
    leftx=(int)(mBezierStart1.x - mTouchToCornerDis/4 - 1);
    rightx= (int) mBezierStart1.x + 1;
    mBackShadowDrawable=mBackShadowDrawableRL;
    }

    Log.i("hmg", "leftx " + leftx
    + " rightx " + rightx);
    canvas.save();
    canvas.clipPath(mPath0);
    canvas.clipPath(mPath1, Region.Op.INTERSECT);
    canvas.drawBitmap(bitmap, 0, 0, null);
    canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y);
    mBackShadowDrawable.setBounds(leftx,
    (int)mBezierStart1.y, rightx,
    (int) (mMaxLength + mBezierStart1.y));
    mBackShadowDrawable.draw(canvas);
    canvas.restore();
    }

    public void setBitmaps(Bitmap bm1, Bitmap bm2, Bitmap bm3) {
    mCurPageBitmap = bm1;
    mCurPageBackBitmap = bm2;
    mNextPageBitmap = bm3;
    }

    @Override
    protected void onDraw(Canvas canvas) {
    canvas.drawColor(0xFFAAAAAA);
    calcPoints();
    drawCurrentPageArea(mCanvas, mCurPageBitmap, mPath0);
    drawNextPageAreaAndShadow(mCanvas, mNextPageBitmap);
    drawCurrentPageShadow(mCanvas);
    canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    }


    /**
    * Author : hmg25
    * Version: 1.0
    * Description : 创建阴影的GradientDrawable
    */
    private void createDrawable() {
    int[] color = { 0x333333, 0xB0333333 };
    mFolderShadowDrawableRL = new GradientDrawable(
    GradientDrawable.Orientation.RIGHT_LEFT, color);
    mFolderShadowDrawableRL
    .setGradientType(GradientDrawable.LINEAR_GRADIENT);

    mFolderShadowDrawableLR = new GradientDrawable(
    GradientDrawable.Orientation.LEFT_RIGHT, color);
    mFolderShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);

    mBackShadowColors = new int[] { 0xFF111111, 0x111111 };
    mBackShadowDrawableRL = new GradientDrawable(
    GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors);
    mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);

    mBackShadowDrawableLR = new GradientDrawable(
    GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors);
    mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);

    mFrontShadowColors = new int[] { 0x80888888, 0x888888 };
    mFrontShadowDrawableVLR = new GradientDrawable(
    GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors);
    mFrontShadowDrawableVLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);
    mFrontShadowDrawableVRL = new GradientDrawable(
    GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors);
    mFrontShadowDrawableVRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);

    mFrontShadowDrawableHTB = new GradientDrawable(
    GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors);
    mFrontShadowDrawableHTB.setGradientType(GradientDrawable.LINEAR_GRADIENT);

    mFrontShadowDrawableHBT = new GradientDrawable(
    GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors);
    mFrontShadowDrawableHBT.setGradientType(GradientDrawable.LINEAR_GRADIENT);
    }


    public void drawCurrentPageShadow(Canvas canvas)
    {

    //注:拖拽顶点的阴影,定位有问题,待修改~~
    double d1 = Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x-mBezierControl1.x);
    // double d3 =(float)Math.cos(d1) * 25*1.414f;
    double d3 =(float) 25/Math.cos(d1) ;
    // float x = (float)(mTouch.x-d3);
    // float y = mTouch.y -(float)Math.sin(d1) * 25*1.414f;
    float x = (float)(mTouch.x-d3);
    float y =(float)( mTouch.y -d3);
    mPath1.reset();
    mPath1.moveTo(x, y);
    mPath1.lineTo(mTouch.x, mTouch.y);
    mPath1.lineTo(mBezierControl1.x, mBezierControl1.y);
    mPath1.lineTo(mBezierStart1.x, mBezierStart1.y);
    mPath1.close();
    float rotateDegrees;
    canvas.save();

    canvas.clipPath(mPath0, Region.Op.XOR);
    canvas.clipPath(mPath1,Region.Op.INTERSECT);
    int leftx;
    int rightx;
    GradientDrawable mCurrentPageShadow;
    if(mIsRTandLB)
    {
    leftx=(int)(mBezierControl1.x);
    rightx= (int)mBezierControl1.x+25;
    mCurrentPageShadow=mFrontShadowDrawableVLR;
    }else
    {
    leftx=(int)(mBezierControl1.x-25);
    rightx= (int) mBezierControl1.x;
    mCurrentPageShadow=mFrontShadowDrawableVRL;
    }
    rotateDegrees= (float)Math.toDegrees(Math.atan2(mTouch.x-mBezierControl1.x,mBezierControl1.y-mTouch.y));
    canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y);

    mCurrentPageShadow.setBounds(leftx, (int)(mBezierControl1.y-500), rightx, (int)(mBezierControl1.y));
    mCurrentPageShadow.draw(canvas);
    canvas.restore();

    mPath1.reset();
    mPath1.moveTo(x, y);
    mPath1.lineTo(mTouch.x, mTouch.y);
    mPath1.lineTo(mBezierControl2.x, mBezierControl2.y);
    mPath1.lineTo(mBezierStart2.x, mBezierStart2.y);
    mPath1.close();
    canvas.save();
    canvas.clipPath(mPath0, Region.Op.XOR);
    canvas.clipPath(mPath1,Region.Op.INTERSECT);

    if(mIsRTandLB)
    {
    leftx=(int)(mBezierControl2.y);
    rightx=(int)(mBezierControl2.y+25);
    mCurrentPageShadow=mFrontShadowDrawableHTB;
    }else
    {
    leftx=(int)(mBezierControl2.y-25);
    rightx=(int)(mBezierControl2.y);
    mCurrentPageShadow=mFrontShadowDrawableHBT;
    }
    rotateDegrees= (float)Math.toDegrees(Math.atan2(mBezierControl2.y-mTouch.y,mBezierControl2.x-mTouch.x));
    canvas.rotate( rotateDegrees, mBezierControl2.x, mBezierControl2.y);
    mCurrentPageShadow.setBounds((int)(mBezierControl2.x-500),leftx , (int)(mBezierControl2.x), rightx );
    mCurrentPageShadow.draw(canvas);
    canvas.restore();
    }

    }

    turntest:

    package sf.hmg.turntest;

    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Window;
    import android.view.WindowManager;

    public class turntest extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(
    WindowManager.LayoutParams.FLAG_FULLSCREEN,
    WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(new PageWidget(this));

    }

    }

    实例1效果图:

    ------------------------------------------------------------------------------------------------------------------------------------------------------

    ------------------------------------------------------------------------------------------------------------------------------------------------------

    实例2代码:

    工程结构图:

    MainActivity:

    package com.xin.book;

    import java.util.ArrayList;
    import java.util.List;

    import android.app.Activity;
    import android.os.Bundle;

    import com.xin.book.view.BookAdapter;
    import com.xin.book.view.BookLayout;

    public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    BookLayout bk = new BookLayout(this);
    List<String> str = new ArrayList<String>();
    str.add("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
    str.add("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
    str.add("ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc");
    str.add("ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd");
    str.add("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
    str.add("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
    BookAdapter ba = new BookAdapter(this);
    ba.addItem(str);
    bk.setPageAdapter(ba);
    setContentView(bk);
    }
    }

    BookAdapter:

    package com.xin.book.view;

    import java.util.ArrayList;
    import java.util.List;

    import android.content.Context;
    import android.graphics.Color;
    import android.view.View;
    import android.view.ViewGroup.LayoutParams;
    import android.widget.FrameLayout;
    import android.widget.TextView;

    import com.xin.book.R;


    public class BookAdapter implements IAdapter{
    private List<String> strList = new ArrayList<String>();

    private Context mContext;
    public BookAdapter(Context context) {
    super();
    this.mContext = context;
    }
    public void addItem(List<String> list){
    strList.addAll(list);
    }
    public int getCount() {
    return strList.size();
    }

    public String getItem(int position) {
    return strList.get(position);
    }

    public long getItemId(int position) {
    return position;
    }

    public View getView(int position) {
    TextView textView = new TextView(mContext);
    textView.setText(strList.get(position));
    textView.setTextColor(Color.BLACK);
    textView.setTextSize(32);
    textView.setBackgroundColor(Color.WHITE);
    textView.setBackgroundResource(R.drawable.ly);
    textView.setPadding(10, 10, 10, 10);
    textView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
    return textView;
    }

    }

    BookLayout:

    package com.xin.book.view;

    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 BookLayout extends FrameLayout {

    public static final String LOG_TAG = "HarHar";
    private int totalPageNum;
    private Context mContext;
    private boolean hasInit = false;
    private final int defaultWidth = 600, defaultHeight = 400;
    private int contentWidth = 0;
    private int contentHeight = 0;
    private View currentPage,middlePage,nextPage,prevPage;
    private LinearLayout invisibleLayout;
    private LinearLayout mainLayout;
    private BookView mBookView;
    private Handler aniEndHandle;
    private static boolean closeBook = false;

    private Corner mSelectCorner;
    private final int clickCornerLen = 250 * 250; // 50dip
    private float scrollX = 0, scrollY = 0;
    private int indexPage = 0;


    private BookState mState;
    private Point aniStartPos;
    private Point aniStopPos;
    private Date aniStartTime;
    private long aniTime = 800;
    private long timeOffset = 10;

    // private Listener mListener;
    private BookAdapter mPageAdapter;

    private GestureDetector mGestureDetector;
    private BookOnGestureListener mGestureListener;

    public BookLayout(Context context) {
    super(context);
    Init(context);
    }

    public BookLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    Init(context);
    }

    public BookLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    Init(context);
    }

    public void setPageAdapter(BookAdapter pa) {
    Log.d(LOG_TAG, "setPageAdapter");
    mPageAdapter = pa;
    }

    public void Init(Context context) {
    Log.d(LOG_TAG, "Init");
    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);
    }

    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();
    mainLayout = new LinearLayout(mContext);
    mainLayout.setLayoutParams(new LayoutParams(contentWidth, contentHeight));
    mainLayout.setBackgroundColor(0xffffffff);
    mState = BookState.READY;

    invisibleLayout = new LinearLayout(mContext);
    invisibleLayout.setLayoutParams(new LayoutParams(contentWidth, contentHeight));


    this.addView(invisibleLayout);
    this.addView(mainLayout);

    mBookView = new BookView(mContext);
    mBookView.setLayoutParams(new LayoutParams(contentWidth, contentHeight));
    this.addView(mBookView);

    updatePageView();
    invalidate();
    } else if (mState == BookState.READY) {
    mBookView.update();
    }
    }

    /**
    * 此方法做过修改,改成一页显示
    */
    public void updatePageView() {
    Log.d(LOG_TAG, "updatePageView");
    if (indexPage < 0 || indexPage > totalPageNum - 1) {
    return;
    }
    invisibleLayout.removeAllViews();
    mainLayout.removeAllViews();

    /*当前页*/
    currentPage = mPageAdapter.getView(indexPage);
    if(currentPage == null){
    currentPage = new WhiteView(mContext);
    }
    currentPage.setLayoutParams(new LayoutParams(contentWidth,contentHeight));
    mainLayout.addView(currentPage);

    /*背景页*/
    middlePage = new WhiteView(mContext);
    middlePage.setLayoutParams(new LayoutParams(contentWidth,contentHeight));
    invisibleLayout.addView(middlePage);

    /*前一页*/
    prevPage = null;
    if(indexPage>0){
    prevPage = mPageAdapter.getView(indexPage-1);
    }
    if(prevPage==null){
    prevPage = new WhiteView(mContext);
    }
    prevPage.setLayoutParams(new LayoutParams(contentWidth,contentHeight));
    invisibleLayout.addView(prevPage);

    /*后一页*/
    nextPage = null;
    if(indexPage<totalPageNum-1){
    nextPage = mPageAdapter.getView(indexPage + 1);
    }
    if(nextPage==null){
    nextPage = new WhiteView(mContext);
    }
    nextPage.setLayoutParams(new LayoutParams(contentWidth,contentHeight));
    invisibleLayout.addView(nextPage);


    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){
    if(scrollX<contentWidth/2){
    aniStopPos = new Point(0,0);
    }else{
    aniStopPos = new Point(2*contentWidth,0);
    }
    }else if(mSelectCorner == Corner.RightTop){
    if(scrollX<contentWidth/2){
    aniStopPos = new Point(-contentWidth,0);
    }else{
    aniStopPos = new Point(contentWidth,0);
    }
    }else if(mSelectCorner == Corner.LeftBottom){
    if(scrollX<contentWidth/2){
    aniStopPos = new Point(0,contentHeight);
    }else{
    aniStopPos = new Point(2*contentWidth,contentHeight);
    }
    }else if(mSelectCorner == Corner.RightBottom){
    if(scrollX<contentWidth/2){
    aniStopPos = new Point(-contentWidth,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 > 0) {
    mSelectCorner = Corner.LeftTop;
    aniStartPos = new Point(0, 0);
    }
    } else if ((x - w) * (x - w) + y * y < clickCornerLen) {
    if (indexPage < totalPageNum - 1) {
    mSelectCorner = Corner.RightTop;
    aniStartPos = new Point(contentWidth, 0);
    }
    } else if (x * x + (y - h) * (y - h) < clickCornerLen) {
    if (indexPage > 0) {
    mSelectCorner = Corner.LeftBottom;
    aniStartPos = new Point(0, contentHeight);
    }
    } else if ((x - w) * (x - w) + (y - h) * (y - h) < clickCornerLen) {
    if (indexPage < totalPageNum - 1) {
    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) {
    if (velocityX < 0) {
    aniStopPos = new Point(0, 0);
    } else {
    aniStopPos = new Point(2*contentWidth, 0);
    }
    }else if( mSelectCorner == Corner.RightTop){
    if (velocityX < 0) {
    aniStopPos = new Point(-contentWidth, 0);
    } else {
    aniStopPos = new Point(contentWidth, 0);
    }
    }else if (mSelectCorner == Corner.LeftBottom ) {
    if (velocityX < 0) {
    aniStopPos = new Point(0, contentHeight);
    } else {
    aniStopPos = new Point(2*contentWidth, contentHeight);
    }
    }else if( mSelectCorner == Corner.RightBottom){
    if (velocityX < 0) {
    aniStopPos = new Point(-contentWidth, 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) {
    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) {
    if (scrollX < contentWidth / 2) {
    aniStopPos = new Point(0, 0);
    } else {
    aniStopPos = new Point(2*contentWidth, 0);
    }
    } else if(mSelectCorner == Corner.RightTop){
    if (scrollX < contentWidth / 2) {
    aniStopPos = new Point(-contentWidth, 0);
    } else {
    aniStopPos = new Point(contentWidth, 0);
    }
    }else if (mSelectCorner == Corner.LeftBottom) {
    if (scrollX < contentWidth / 2) {
    aniStopPos = new Point(0, contentHeight);
    } else {
    aniStopPos = new Point(2*contentWidth, contentHeight);
    }
    }else if(mSelectCorner == Corner.RightBottom){
    if (scrollX < contentWidth / 2) {
    aniStopPos = new Point(-contentWidth, 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, " + contentWidth + " height:" + contentHeight);
    }



    class BookView extends SurfaceView implements SurfaceHolder.Callback {
    DrawThread dt;
    SurfaceHolder surfaceHolder;
    Paint mDarkPaint = new Paint();
    Paint mPaint = new Paint();
    Bitmap tmpBmp = Bitmap.createBitmap(contentWidth, 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() {
    if (dt == null) {
    Log.d(LOG_TAG, "startAnimation");
    dt = new DrawThread(this, getHolder());
    dt.start();
    }
    }

    public void stopAnimation() {
    Log.d(LOG_TAG, "stopAnimation");
    if (dt != null) {
    dt.flag = false;
    Thread t = dt;
    dt = null;
    t.interrupt();
    }
    }

    public void drawLT(Canvas canvas) {
    double dx = contentWidth - scrollX, dy = scrollY;
    double len = Math.sqrt(dx * dx + dy * dy);
    if (len > contentWidth) {
    scrollX = (float)(contentWidth - contentWidth*dx/len);
    scrollY = (float)(contentWidth*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, scrollY);
    m.postRotate((float) (arc), scrollX, scrollY);

    middlePage.draw(mCanvas);

    Paint ps = new Paint();
    Shader lg1 = new LinearGradient(contentWidth , 0, contentWidth - (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 , contentHeight, ps);
    canvas.drawBitmap(tmpBmp, m, bmpPaint);

    prevPage.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 , 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 , 0);
    path.lineTo(contentWidth , 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 , 0);
    path.lineTo(contentWidth , contentHeight);
    path.lineTo((float) p3, contentHeight);
    path.close();
    } else {
    path.moveTo((float) p1, 0);
    path.lineTo(contentWidth , 0);
    path.lineTo(contentWidth , 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 = contentWidth - scrollX, dy = contentHeight-scrollY;
    double len = Math.sqrt(dx * dx + dy * dy);
    if (len > contentWidth ) {
    scrollX = (float) (contentWidth-contentWidth * dx /len);
    scrollY = (float) (contentHeight-contentWidth * 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 , scrollY - contentHeight);
    m.postRotate((float) (-arc), scrollX, scrollY);

    middlePage.draw(mCanvas);

    Paint ps = new Paint();
    Shader lg1 = new LinearGradient(contentWidth , contentHeight, contentWidth - (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, contentHeight, ps);
    canvas.drawBitmap(tmpBmp, m, bmpPaint);

    prevPage.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, 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 , 0);
    path.lineTo(contentWidth , 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 , 0);
    path.lineTo(contentWidth , contentHeight);
    path.lineTo((float) p1, contentHeight);
    path.close();
    } else {
    path.moveTo(0, 0);
    path.lineTo(contentWidth , 0);
    path.lineTo(contentWidth , 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 , dy = scrollY;
    double len = Math.sqrt(dx * dx + dy * dy);
    if (len > contentWidth) {
    scrollX = (float) (contentWidth * dx /len);
    scrollY = (float) (contentWidth * 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);

    middlePage.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, contentHeight, ps);
    canvas.drawBitmap(tmpBmp, m, bmpPaint);

    nextPage.draw(mCanvas);
    Shader lg2 = new LinearGradient(scrollX - contentWidth, scrollY, contentWidth, 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, contentHeight, ps);

    arc = arc * Math.PI / 360;
    Path path = new Path();
    double r = Math.sqrt(px * px + py * py);
    double p1 = contentWidth - 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 - (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 , (float) p2);
    path.lineTo(contentWidth , contentHeight);
    path.lineTo(0, contentHeight);
    path.close();
    }
    mCanvas.drawPath(path, ivisiblePaint);
    canvas.drawBitmap(tmpBmp, 0 , 0, null);
    }

    public void drawRB(Canvas canvas) {
    double dx = scrollX , dy = contentHeight - scrollY;
    double len = Math.sqrt(dx * dx + dy * dy);
    if (len > contentWidth ) {
    scrollX = (float) (contentWidth * dx /len);
    scrollY = (float) (contentHeight-contentWidth * 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);

    middlePage.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 , contentHeight, ps);
    canvas.drawBitmap(tmpBmp, m, bmpPaint);

    nextPage.draw(mCanvas);
    Shader lg2 = new LinearGradient(scrollX - contentWidth , scrollY, contentWidth , 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 , contentHeight, ps);

    arc = arc * Math.PI / 360;
    Path path = new Path();
    double r = Math.sqrt(px * px + py * py);
    double p1 = contentWidth - 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 - (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 , 0);
    path.lineTo(contentWidth , contentHeight - (float) p2);
    path.lineTo((float) p1, contentHeight);
    path.lineTo(0, contentHeight);
    path.close();
    }
    mCanvas.drawPath(path, ivisiblePaint);
    canvas.drawBitmap(tmpBmp, 0 , 0, null);
    }

    public void drawPrevPageEnd(Canvas canvas) {
    prevPage.draw(mCanvas);
    canvas.drawBitmap(tmpBmp, 0, 0, null);
    }

    public void drawNextPageEnd(Canvas canvas) {
    nextPage.draw(mCanvas);
    canvas.drawBitmap(tmpBmp, contentWidth, 0, null);
    }

    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);
    try {
    synchronized (surfaceHolder) {
    doDraw(canvas);
    }
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    if (canvas != null) {
    surfaceHolder.unlockCanvasAndPost(canvas);
    }
    }
    }

    protected void doDraw(Canvas canvas) {
    Log.d(LOG_TAG, "bookView doDraw");
    mainLayout.draw(canvas);

    }

    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;
    }
    }
    }

    public boolean getAnimateData() {
    Log.d(LOG_TAG, "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;
    scrollX =(float)(sx*t/time+aniStartPos.x);
    double sy = aniStopPos.y-aniStartPos.y;
    scrollY = (float)(sy*t/time+aniStartPos.y);
    return true;
    }
    }

    public void handleAniEnd(Canvas canvas) {
    Log.d(LOG_TAG, "handleAniEnd");
    if (closeBook) {
    closeBook = false;
    if (mSelectCorner == Corner.LeftTop || mSelectCorner == Corner.LeftBottom) {
    if (scrollX > contentWidth / 2) {
    indexPage -= 1;
    mBookView.drawPrevPageEnd(canvas);
    aniEndHandle.post(new Runnable() {
    public void run() {
    updatePageView();
    }
    });
    } else {
    mBookView.doDraw(canvas);
    }
    } else if (mSelectCorner == Corner.RightTop || mSelectCorner == Corner.RightBottom) {
    if (scrollX < contentWidth / 2) {
    indexPage += 1;
    mBookView.drawNextPageEnd(canvas);
    aniEndHandle.post(new Runnable() {
    public void run() {
    updatePageView();
    }
    });
    } else {
    mBookView.doDraw(canvas);
    }
    }
    mSelectCorner = Corner.None;
    mState = BookState.READY;
    } else {
    mState = BookState.TRACKING;
    }
    mBookView.stopAnimation();
    // aniEndHandle.post(new Runnable() {
    // public void run() {
    ////
    BookLayout.this.invalidate();
    // }
    // });
    }

    class WhiteView extends View {
    public WhiteView(Context context) {
    super(context);
    }

    protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawColor(Color.WHITE);
    }
    }

    public class DrawThread extends Thread {
    BookView bv;
    SurfaceHolder surfaceHolder;
    boolean flag = false;
    int sleepSpan = 30;

    public DrawThread(BookView bv, SurfaceHolder surfaceHolder) {
    this.bv = bv;
    this.surfaceHolder = surfaceHolder;
    this.flag = true;
    }

    public void run() {
    Canvas canvas = null;
    while (flag) {
    try {
    canvas = surfaceHolder.lockCanvas(null);
    if (canvas == null)
    continue;
    synchronized (surfaceHolder) {
    if (mState == BookState.ABOUT_TO_ANIMATE || mState == BookState.ANIMATING) {
    bv.doDraw(canvas);
    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) {
    surfaceHolder.unlockCanvasAndPost(canvas);
    }
    }
    try {
    Thread.sleep(sleepSpan);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
    }
    }

    BookState:

    package com.xin.book.view;

    public enum BookState {
    ABOUT_TO_ANIMATE, ANIMATING, ANIMATE_END, READY, TRACKING
    }

    Corner:

    package com.xin.book.view;

    public enum Corner {
    LeftTop, RightTop, LeftBottom, RightBottom, None
    }

    IAdapter:

    package com.xin.book.view;

    import android.view.View;

    public interface IAdapter {
    public int getCount();
    public String getItem(int position);
    public long getItemId(int position);
    public View getView(int position);
    }

    IBook:

    package com.xin.book.view;

    import android.view.View;

    public interface IBook {
    public View getView(int position);

    public int getCount();
    }

    IListener:

    package com.xin.book.view;

    public interface IListener {
    public void onPrevPage();

    public void onNextPage();

    public void onInit();
    }

    实例2效果图:

    完O(∩_∩)O~

    本文来自:http://www.cnblogs.com/hanyonglu/archive/2012/02/13/2348585.html

  • 相关阅读:
    博客园的Windows Mobile开发专栏
    使大脑迟钝的9种不良习惯
    javascript中实现QueryString的function
    DeviceIoControl实现异步的方法总结
    List of Scientist`s Names
    制版经验谈
    AVRUSB技术探讨(转)
    unexpected WaitForXfer() behavior
    openMP讨论帖
    全角半角SBCDBC
  • 原文地址:https://www.cnblogs.com/jh5240/p/2432112.html
Copyright © 2011-2022 走看看