android酷炫翻页效果+图形分析

jopen 12年前

 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;      }    }
/**   *  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;      }  }
 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;              }            });      }  }
来自:http://www.blogjava.net/wangxinsh55/archive/2011/09/21/359146.html