posts - 495,comments - 227,trackbacks - 0


package sf.hmg.turntest;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Region;
import android.graphics.drawable.GradientDrawable;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

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 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;
    ColorMatrixColorFilter mColorMatrixFilter;
    Matrix mMatrix;
    
float[] mMatrixArray = { 000000001.0f };

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

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

    Paint mPaint;

    Scroller mScroller;

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

        mPaint 
= new Paint();
        mPaint.setStyle(Paint.Style.FILL);

        ColorMatrix cm 
= new ColorMatrix();
        
float array[] = { 0.55f00080.0f00.55f0080.0f00,
                
0.55f080.0f0000.2f0 };
        cm.set(array);
        mColorMatrixFilter 
= new ColorMatrixColorFilter(cm);
        mMatrix 
= new Matrix();
        mScroller 
= new Scroller(getContext());

        mTouch.x 
= 0.01f// 不让x,y为0,否则在点计算时会有问题
        mTouch.y = 0.01f;
    }

    
/**
     * Author : hmg25 Version: 1.0 Description : 计算拖拽点对应的拖拽脚
     
*/
    
public 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;
    }

    
public boolean doTouchEvent(MotionEvent event) {
        
// TODO Auto-generated method stub
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            mTouch.x 
= event.getX();
            mTouch.y 
= event.getY();
            
this.postInvalidate();
        }
        
if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mTouch.x 
= event.getX();
            mTouch.y 
= event.getY();
            
// calcCornerXY(mTouch.x, mTouch.y);
            
// this.postInvalidate();
        }
        
if (event.getAction() == MotionEvent.ACTION_UP) {
            
if (canDragOver()) {
                startAnimation(
1200);
            } 
else {
                mTouch.x 
= mCornerX - 0.09f;
                mTouch.y 
= mCornerY - 0.09f;
            }

            
this.postInvalidate();
        }
        
// return super.onTouchEvent(event);
        return true;
    }

    
/**
     * Author : hmg25 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;

        
// 当mBezierStart1.x < 0或者mBezierStart1.x > 480时
        
// 如果继续翻页,会出现BUG故在此限制
        if (mTouch.x > 0 && mTouch.x < mWidth) {
            
if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth) {
                
if (mBezierStart1.x < 0)
                    mBezierStart1.x 
= mWidth - mBezierStart1.x;

                
float f1 = Math.abs(mCornerX - mTouch.x);
                
float f2 = mWidth * f1 / mBezierStart1.x;
                mTouch.x 
= Math.abs(mCornerX - f2);

                
float f3 = Math.abs(mCornerX - mTouch.x)
                        
* Math.abs(mCornerY - mTouch.y) / f1;
                mTouch.y 
= Math.abs(mCornerY - f3);

                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;
            }
        }
        mBezierStart2.x 
= mCornerX;
        mBezierStart2.y 
= mBezierControl2.y - (mCornerY - mBezierControl2.y)
                
/ 2;

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

    
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, 
00null);
        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));
        
int leftx;
        
int rightx;
        GradientDrawable mBackShadowDrawable;
        
if (mIsRTandLB) {
            leftx 
= (int) (mBezierStart1.x);
            rightx 
= (int) (mBezierStart1.x + mTouchToCornerDis / 4);
            mBackShadowDrawable 
= mBackShadowDrawableLR;
        } 
else {
            leftx 
= (int) (mBezierStart1.x - mTouchToCornerDis / 4);
            rightx 
= (int) mBezierStart1.x;
            mBackShadowDrawable 
= mBackShadowDrawableRL;
        }
        canvas.save();
        canvas.clipPath(mPath0);
        canvas.clipPath(mPath1, Region.Op.INTERSECT);
        canvas.drawBitmap(bitmap, 
00null);
        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) {
        mCurPageBitmap 
= bm1;
        mNextPageBitmap 
= bm2;
    }

    
public void setScreen(int w, int h) {
        mWidth 
= w;
        mHeight 
= h;
    }

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

    
/**
     * Author : hmg25 Version: 1.0 Description : 创建阴影的GradientDrawable
     
*/
    
private void createDrawable() {
        
int[] color = { 0x3333330xb0333333 };
        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[] { 0xff1111110x111111 };
        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[] { 0x801111110x111111 };
        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);
    }

    
/**
     * Author : hmg25 Version: 1.0 Description : 绘制翻起页的阴影
     
*/
    
public void drawCurrentPageShadow(Canvas canvas) {
        
double degree;
        
if (mIsRTandLB) {
            degree 
= Math.PI
                    
/ 4
                    
- Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x
                            
- mBezierControl1.x);
        } 
else {
            degree 
= Math.PI
                    
/ 4
                    
- Math.atan2(mTouch.y - mBezierControl1.y, mTouch.x
                            
- mBezierControl1.x);
        }
        
// 翻起页阴影顶点与touch点的距离
        double d1 = (float25 * 1.414 * Math.cos(degree);
        
double d2 = (float25 * 1.414 * Math.sin(degree);
        
float x = (float) (mTouch.x + d1);
        
float y;
        
if (mIsRTandLB) {
            y 
= (float) (mTouch.y + d2);
        } 
else {
            y 
= (float) (mTouch.y - d2);
        }
        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 + 1;
            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 - mMaxLength), 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 + 1);
            mCurrentPageShadow 
= mFrontShadowDrawableHBT;
        }
        rotateDegrees 
= (float) Math.toDegrees(Math.atan2(mBezierControl2.y
                
- mTouch.y, mBezierControl2.x - mTouch.x));
        canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y);
        
float temp;
        
if (mBezierControl2.y < 0)
            temp 
= mBezierControl2.y - mHeight;
        
else
            temp 
= mBezierControl2.y;

        
int hmg = (int) Math.hypot(mBezierControl2.x, temp);
        
if (hmg > mMaxLength)
            mCurrentPageShadow
                    .setBounds((
int) (mBezierControl2.x - 25- hmg, leftx,
                            (
int) (mBezierControl2.x + mMaxLength) - hmg,
                            rightx);
        
else
            mCurrentPageShadow.setBounds(
                    (
int) (mBezierControl2.x - mMaxLength), leftx,
                    (
int) (mBezierControl2.x), rightx);

        
// Log.i("hmg", "mBezierControl2.x   " + mBezierControl2.x
        
// + "  mBezierControl2.y  " + mBezierControl2.y);
        mCurrentPageShadow.draw(canvas);
        canvas.restore();
    }

    
/**
     * Author : hmg25 Version: 1.0 Description : 绘制翻起页背面
     
*/
    
private void drawCurrentBackArea(Canvas canvas, Bitmap bitmap) {
        
int i = (int) (mBezierStart1.x + mBezierControl1.x) / 2;
        
float f1 = Math.abs(i - mBezierControl1.x);
        
int i1 = (int) (mBezierStart2.y + mBezierControl2.y) / 2;
        
float f2 = Math.abs(i1 - mBezierControl2.y);
        
float f3 = Math.min(f1, f2);
        mPath1.reset();
        mPath1.moveTo(mBeziervertex2.x, mBeziervertex2.y);
        mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y);
        mPath1.lineTo(mBezierEnd1.x, mBezierEnd1.y);
        mPath1.lineTo(mTouch.x, mTouch.y);
        mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y);
        mPath1.close();
        GradientDrawable mFolderShadowDrawable;
        
int left;
        
int right;
        
if (mIsRTandLB) {
            left 
= (int) (mBezierStart1.x - 1);
            right 
= (int) (mBezierStart1.x + f3 + 1);
            mFolderShadowDrawable 
= mFolderShadowDrawableLR;
        } 
else {
            left 
= (int) (mBezierStart1.x - f3 - 1);
            right 
= (int) (mBezierStart1.x + 1);
            mFolderShadowDrawable 
= mFolderShadowDrawableRL;
        }
        canvas.save();
        canvas.clipPath(mPath0);
        canvas.clipPath(mPath1, Region.Op.INTERSECT);

        mPaint.setColorFilter(mColorMatrixFilter);

        
float dis = (float) Math.hypot(mCornerX - mBezierControl1.x,
                mBezierControl2.y 
- mCornerY);
        
float f8 = (mCornerX - mBezierControl1.x) / dis;
        
float f9 = (mBezierControl2.y - mCornerY) / dis;
        mMatrixArray[
0= 1 - 2 * f9 * f9;
        mMatrixArray[
1= 2 * f8 * f9;
        mMatrixArray[
3= mMatrixArray[1];
        mMatrixArray[
4= 1 - 2 * f8 * f8;
        mMatrix.reset();
        mMatrix.setValues(mMatrixArray);
        mMatrix.preTranslate(
-mBezierControl1.x, -mBezierControl1.y);
        mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y);
        canvas.drawBitmap(bitmap, mMatrix, mPaint);
        
// canvas.drawBitmap(bitmap, mMatrix, null);
        mPaint.setColorFilter(null);
        canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y);
        mFolderShadowDrawable.setBounds(left, (
int) mBezierStart1.y, right,
                (
int) (mBezierStart1.y + mMaxLength));
        mFolderShadowDrawable.draw(canvas);
        canvas.restore();
    }

    
public void computeScroll() {
        
super.computeScroll();
        
if (mScroller.computeScrollOffset()) {
            
float x = mScroller.getCurrX();
            
float y = mScroller.getCurrY();
            mTouch.x 
= x;
            mTouch.y 
= y;
            postInvalidate();
        }
    }

    
private void startAnimation(int delayMillis) {
        
int dx, dy;
        
// dx 水平方向滑动的距离,负值会使滚动向左滚动
        
// dy 垂直方向滑动的距离,负值会使滚动向上滚动
        if (mCornerX > 0) {
            dx 
= -(int) (mWidth + mTouch.x);
        } 
else {
            dx 
= (int) (mWidth - mTouch.x + mWidth);
        }
        
if (mCornerY > 0) {
            dy 
= (int) (mHeight - mTouch.y);
        } 
else {
            dy 
= (int) (1 - mTouch.y); // 防止mTouch.y最终变为0
        }
        mScroller.startScroll((
int) mTouch.x, (int) mTouch.y, dx, dy,
                delayMillis);
    }

    
public void abortAnimation() {
        
if (!mScroller.isFinished()) {
            mScroller.abortAnimation();
        }
    }

    
public boolean canDragOver() {
        
if (mTouchToCornerDis > mWidth / 10)
            
return true;
        
return false;
    }

    
/**
     * Author : hmg25 Version: 1.0 Description : 是否从左边翻向右边
     
*/
    
public boolean DragToRight() {
        
if (mCornerX > 0)
            
return false;
        
return true;
    }

}

/**
 *  Author :  hmg25
 *  Description :
 
*/
package sf.hmg.turntest;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
import java.util.Vector;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;

public class BookPageFactory {

    
private File book_file = null;
    
private MappedByteBuffer m_mbBuf = null;
    
private int m_mbBufLen = 0;
    
private int m_mbBufBegin = 0;
    
private int m_mbBufEnd = 0;
    
private String m_strCharsetName = "GBK";
    
private Bitmap m_book_bg = null;
    
private int mWidth;
    
private int mHeight;

    
private Vector<String> m_lines = new Vector<String>();

    
private int m_fontSize = 24;
    
private int m_textColor = Color.BLACK;
    
private int m_backColor = 0xffff9e85// 背景颜色
    private int marginWidth = 15// 左右与边缘的距离
    private int marginHeight = 20// 上下与边缘的距离

    
private int mLineCount; // 每页可以显示的行数
    private float mVisibleHeight; // 绘制内容的宽
    private float mVisibleWidth; // 绘制内容的宽
    private boolean m_isfirstPage,m_islastPage;

    
// private int m_nLineSpaceing = 5;

    
private Paint mPaint;

    
public BookPageFactory(int w, int h) {
        
// TODO Auto-generated constructor stub
        mWidth = w;
        mHeight 
= h;
        mPaint 
= new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setTextAlign(Align.LEFT);
        mPaint.setTextSize(m_fontSize);
        mPaint.setColor(m_textColor);
        mVisibleWidth 
= mWidth - marginWidth * 2;
        mVisibleHeight 
= mHeight - marginHeight * 2;
        mLineCount 
= (int) (mVisibleHeight / m_fontSize); // 可显示的行数
    }

    
public void openbook(String strFilePath) throws IOException {
        book_file 
= new File(strFilePath);
        
long lLen = book_file.length();
        m_mbBufLen 
= (int) lLen;
        m_mbBuf 
= new RandomAccessFile(book_file, "r").getChannel().map(
                FileChannel.MapMode.READ_ONLY, 
0, lLen);
    }
    

    
protected byte[] readParagraphBack(int nFromPos) {
        
int nEnd = nFromPos;
        
int i;
        
byte b0, b1;
        
if (m_strCharsetName.equals("UTF-16LE")) {
            i 
= nEnd - 2;
            
while (i > 0) {
                b0 
= m_mbBuf.get(i);
                b1 
= m_mbBuf.get(i + 1);
                
if (b0 == 0x0a && b1 == 0x00 && i != nEnd - 2) {
                    i 
+= 2;
                    
break;
                }
                i
--;
            }

        } 
else if (m_strCharsetName.equals("UTF-16BE")) {
            i 
= nEnd - 2;
            
while (i > 0) {
                b0 
= m_mbBuf.get(i);
                b1 
= m_mbBuf.get(i + 1);
                
if (b0 == 0x00 && b1 == 0x0a && i != nEnd - 2) {
                    i 
+= 2;
                    
break;
                }
                i
--;
            }
        } 
else {
            i 
= nEnd - 1;
            
while (i > 0) {
                b0 
= m_mbBuf.get(i);
                
if (b0 == 0x0a && i != nEnd - 1) {
                    i
++;
                    
break;
                }
                i
--;
            }
        }
        
if (i < 0)
            i 
= 0;
        
int nParaSize = nEnd - i;
        
int j;
        
byte[] buf = new byte[nParaSize];
        
for (j = 0; j < nParaSize; j++) {
            buf[j] 
= m_mbBuf.get(i + j);
        }
        
return buf;
    }


    
// 读取上一段落
    protected byte[] readParagraphForward(int nFromPos) {
        
int nStart = nFromPos;
        
int i = nStart;
        
byte b0, b1;
        
// 根据编码格式判断换行
        if (m_strCharsetName.equals("UTF-16LE")) {
            
while (i < m_mbBufLen - 1) {
                b0 
= m_mbBuf.get(i++);
                b1 
= m_mbBuf.get(i++);
                
if (b0 == 0x0a && b1 == 0x00) {
                    
break;
                }
            }
        } 
else if (m_strCharsetName.equals("UTF-16BE")) {
            
while (i < m_mbBufLen - 1) {
                b0 
= m_mbBuf.get(i++);
                b1 
= m_mbBuf.get(i++);
                
if (b0 == 0x00 && b1 == 0x0a) {
                    
break;
                }
            }
        } 
else {
            
while (i < m_mbBufLen) {
                b0 
= m_mbBuf.get(i++);
                
if (b0 == 0x0a) {
                    
break;
                }
            }
        }
        
int nParaSize = i - nStart;
        
byte[] buf = new byte[nParaSize];
        
for (i = 0; i < nParaSize; i++) {
            buf[i] 
= m_mbBuf.get(nFromPos + i);
        }
        
return buf;
    }

    
protected Vector<String> pageDown() {
        String strParagraph 
= "";
        Vector
<String> lines = new Vector<String>();
        
while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen) {
            
byte[] paraBuf = readParagraphForward(m_mbBufEnd); // 读取一个段落
            m_mbBufEnd += paraBuf.length;
            
try {
                strParagraph 
= new String(paraBuf, m_strCharsetName);
            } 
catch (UnsupportedEncodingException e) {
                
// TODO Auto-generated catch block
                e.printStackTrace();
            }
            String strReturn 
= "";
            
if (strParagraph.indexOf("\r\n"!= -1) {
                strReturn 
= "\r\n";
                strParagraph 
= strParagraph.replaceAll("\r\n""");
            } 
else if (strParagraph.indexOf("\n"!= -1) {
                strReturn 
= "\n";
                strParagraph 
= strParagraph.replaceAll("\n""");
            }

            
if (strParagraph.length() == 0) {
                lines.add(strParagraph);
            }
            
while (strParagraph.length() > 0) {
                
int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth,
                        
null);
                lines.add(strParagraph.substring(
0, nSize));
                strParagraph 
= strParagraph.substring(nSize);
                
if (lines.size() >= mLineCount) {
                    
break;
                }
            }
            
if (strParagraph.length() != 0) {
                
try {
                    m_mbBufEnd 
-= (strParagraph + strReturn)
                            .getBytes(m_strCharsetName).length;
                } 
catch (UnsupportedEncodingException e) {
                    
// TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        
return lines;
    }

    
protected void pageUp() {
        
if (m_mbBufBegin < 0)
            m_mbBufBegin 
= 0;
        Vector
<String> lines = new Vector<String>();
        String strParagraph 
= "";
        
while (lines.size() < mLineCount && m_mbBufBegin > 0) {
            Vector
<String> paraLines = new Vector<String>();
            
byte[] paraBuf = readParagraphBack(m_mbBufBegin);
            m_mbBufBegin 
-= paraBuf.length;
            
try {
                strParagraph 
= new String(paraBuf, m_strCharsetName);
            } 
catch (UnsupportedEncodingException e) {
                
// TODO Auto-generated catch block
                e.printStackTrace();
            }
            strParagraph 
= strParagraph.replaceAll("\r\n""");
            strParagraph 
= strParagraph.replaceAll("\n""");

            
if (strParagraph.length() == 0) {
                paraLines.add(strParagraph);
            }
            
while (strParagraph.length() > 0) {
                
int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth,
                        
null);
                paraLines.add(strParagraph.substring(
0, nSize));
                strParagraph 
= strParagraph.substring(nSize);
            }
            lines.addAll(
0, paraLines);
        }
        
while (lines.size() > mLineCount) {
            
try {
                m_mbBufBegin 
+= lines.get(0).getBytes(m_strCharsetName).length;
                lines.remove(
0);
            } 
catch (UnsupportedEncodingException e) {
                
// TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        m_mbBufEnd 
= m_mbBufBegin;
        
return;
    }

    
protected void prePage() throws IOException {
        
if (m_mbBufBegin <= 0) {
            m_mbBufBegin 
= 0;
            m_isfirstPage
=true;
            
return;
        }
else m_isfirstPage=false;
        m_lines.clear();
        pageUp();
        m_lines 
= pageDown();
    }

    
public void nextPage() throws IOException {
        
if (m_mbBufEnd >= m_mbBufLen) {
            m_islastPage
=true;
            
return;
        }
else m_islastPage=false;
        m_lines.clear();
        m_mbBufBegin 
= m_mbBufEnd;
        m_lines 
= pageDown();
    }

    
public void onDraw(Canvas c) {
        
if (m_lines.size() == 0)
            m_lines 
= pageDown();
        
if (m_lines.size() > 0) {
            
if (m_book_bg == null)
                c.drawColor(m_backColor);
            
else
                c.drawBitmap(m_book_bg, 
00null);
            
int y = marginHeight;
            
for (String strLine : m_lines) {
                y 
+= m_fontSize;
                c.drawText(strLine, marginWidth, y, mPaint);
            }
        }
        
float fPercent = (float) (m_mbBufBegin * 1.0 / m_mbBufLen);
        DecimalFormat df 
= new DecimalFormat("#0.0");
        String strPercent 
= df.format(fPercent * 100+ "%";
        
int nPercentWidth = (int) mPaint.measureText("999.9%"+ 1;
        c.drawText(strPercent, mWidth 
- nPercentWidth, mHeight - 5, mPaint);
    }

    
public void setBgBitmap(Bitmap BG) {
        m_book_bg 
= BG;
    }
    
    
public boolean isfirstPage() {
        
return m_isfirstPage;
    }
    
public boolean islastPage() {
        
return m_islastPage;
    }
}

package sf.hmg.turntest;

import java.io.IOException;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

public class turntest extends Activity {
    
/** Called when the activity is first created. */
    
private PageWidget mPageWidget;
    Bitmap mCurPageBitmap, mNextPageBitmap;
    Canvas mCurPageCanvas, mNextPageCanvas;
    BookPageFactory pagefactory;

    @Override
    
public void onCreate(Bundle savedInstanceState) {
        
super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        mPageWidget 
= new PageWidget(this);
        setContentView(mPageWidget);

        mCurPageBitmap 
= Bitmap.createBitmap(480800, Bitmap.Config.ARGB_8888);
        mNextPageBitmap 
= Bitmap
                .createBitmap(
480800, Bitmap.Config.ARGB_8888);

        mCurPageCanvas 
= new Canvas(mCurPageBitmap);
        mNextPageCanvas 
= new Canvas(mNextPageBitmap);
        pagefactory 
= new BookPageFactory(480800);

        pagefactory.setBgBitmap(BitmapFactory.decodeResource(
                
this.getResources(), R.drawable.bg));

        
try {
            pagefactory.openbook(
"/sdcard/test.txt");
            pagefactory.onDraw(mCurPageCanvas);
        } 
catch (IOException e1) {
            
// TODO Auto-generated catch block
            e1.printStackTrace();
            Toast.makeText(
this"电子书不存在,请将《test.txt》放在SD卡根目录下",
                    Toast.LENGTH_SHORT).show();
        }

        mPageWidget.setBitmaps(mCurPageBitmap, mCurPageBitmap);

        mPageWidget.setOnTouchListener(
new OnTouchListener() {
            @Override
            
public boolean onTouch(View v, MotionEvent e) {
                
// TODO Auto-generated method stub
                
                
boolean ret=false;
                
if (v == mPageWidget) {
                    
if (e.getAction() == MotionEvent.ACTION_DOWN) {
                        mPageWidget.abortAnimation();
                        mPageWidget.calcCornerXY(e.getX(), e.getY());

                        pagefactory.onDraw(mCurPageCanvas);
                        
if (mPageWidget.DragToRight()) {
                            
try {
                                pagefactory.prePage();
                            } 
catch (IOException e1) {
                                
// TODO Auto-generated catch block
                                e1.printStackTrace();
                            }                        
                            
if(pagefactory.isfirstPage())return false;
                            pagefactory.onDraw(mNextPageCanvas);
                        } 
else {
                            
try {
                                pagefactory.nextPage();
                            } 
catch (IOException e1) {
                                
// TODO Auto-generated catch block
                                e1.printStackTrace();
                            }
                            
if(pagefactory.islastPage())return false;
                            pagefactory.onDraw(mNextPageCanvas);
                        }
                        mPageWidget.setBitmaps(mCurPageBitmap, mNextPageBitmap);
                    }
                 
                     ret 
= mPageWidget.doTouchEvent(e);
                    
return ret;
                }
                
return false;
            }

        });
    }
}
posted on 2011-09-21 11:59 SIMONE 阅读(11082) 评论(2)  编辑  收藏 所属分类: android

FeedBack:
# re: android酷炫翻页效果+图形分析
2011-11-19 15:19 | veallytong
转人家的有什么意思?  回复  更多评论
  
# re: android酷炫翻页效果+图形分析[未登录]
2015-04-21 14:58 | 123
@veallytong
看不出来你自己的分析在哪里。。。。。。。。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: