android酷炫翻頁效果+圖形分析

jopen 12年前發布 | 44K 次閱讀 Android開發 移動開發 Android

 android酷炫翻頁效果+圖形分析

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 = { 0, 0, 0, 0, 0, 0, 0, 0, 1.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.55f, 0, 0, 0, 80.0f, 0, 0.55f, 0, 0, 80.0f, 0, 0,
            0.55f, 0, 80.0f, 0, 0, 0, 0.2f, 0 };
    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, 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));
    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, 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) {
    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 = { 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[] { 0x80111111, 0x111111 };
    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 = (float) 25 * 1.414 * Math.cos(degree);
    double d2 = (float) 25 * 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;
}

}</pre>

/**

  • 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, 0, 0, null);
        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;
}

}</pre>

 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(480, 800, Bitmap.Config.ARGB_8888);
    mNextPageBitmap = Bitmap
            .createBitmap(480, 800, Bitmap.Config.ARGB_8888);

    mCurPageCanvas = new Canvas(mCurPageBitmap);
    mNextPageCanvas = new Canvas(mNextPageBitmap);
    pagefactory = new BookPageFactory(480, 800);

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

    });
}

}</pre>來自:http://www.blogjava.net/wangxinsh55/archive/2011/09/21/359146.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!