android 電子書翻頁效果
- PageWidget
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;
}
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;
}
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 + 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);
}
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);
}
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();
}
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;
}
public boolean DragToRight() {
if (mCornerX > 0)
return false;
return true;
}
}
2 BookPageFactory
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;
}
}
3
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 BookActivity extends Activity {
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;
}
});
}
}
相關文章
- 6個超炫酷的HTML5電子書翻頁動畫HTML動畫
- css翻頁效果CSS
- Android 翻頁效果加蘋果桌面應用抖動效果Android蘋果
- Android自定義View——從零開始實現書籍翻頁效果(二)AndroidView
- Android自定義View——從零開始實現書籍翻頁效果(四)AndroidView
- Android自定義View——從零開始實現書籍翻頁效果(三)AndroidView
- Android自定義View——從零開始實現書籍翻頁效果(一)AndroidView
- iBooker:中文翻譯資料電子書大全
- 我翻譯電子書的常用工具
- [翻譯]關於電子書的思考 by Tim O'Reilly
- Android自定義View——從零開始實現書籍翻頁效果(效能優化篇)AndroidView優化
- 安卓觸控手勢翻頁製作電子相簿安卓
- 推薦12款實用的 JavaScript 書頁翻轉效果外掛JavaScript
- 分享電子書
- css3實現的書本立體翻頁效果程式碼例項CSSS3
- python電子書Python
- 電子書DRM破解
- ul>li*3 實現翻書動畫效果動畫
- ppt製作的翻書效果及教程
- Android自定義View——從零開始實現覆蓋翻頁效果AndroidView
- Android程式設計師必讀電子書推薦Android程式設計師
- 《細說網頁製作》pdf電子書免費下載網頁
- html and css3 js製作翻頁書效果id1099-網頁前端設計HTMLCSSS3JS網頁前端
- 電子書閱讀 AppAPP
- python電子書: djangoPythonDjango
- Android一種翻板式互動效果Android
- 《Head First Android》讀後感,電子書PDF下載Android
- Android實現翻頁功能原理Android
- HTML53D翻書效果(雙面效應)HTML3D
- 實現報表滾動到底部翻頁效果
- Flutter實戰動畫番外篇-翻頁效果實現Flutter動畫
- 電子書生成工具Vellum for MacMac
- (轉)[it-ebooks]電子書列表
- 使用Gitbook製作電子書Git
- 電子書:初等演算法演算法
- 電子書製作軟體
- 怎麼實現一個3d翻書效果3D
- OneClock的翻頁時鐘效果是如何實現的