这篇文章是在参考了别人的博客基础上,修改了其中一个翻页bug,并且加了详细注释,学习使用。
先看效果
其中使用了贝赛尔曲线原理,关于贝赛尔曲线的知识,推荐大家看下http://blog.youkuaiyun.com/hmg25的博客
主函数
package com.zhang;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
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 TurnBook 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);//设置分辨率为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) {
//停止动画。与forceFinished(boolean)相反,Scroller滚动到最终x与y位置时中止动画。
mPageWidget.abortAnimation();
//计算拖拽点对应的拖拽角
mPageWidget.calcCornerXY(e.getX(), e.getY());
//将文字绘于当前页
pagefactory.onDraw(mCurPageCanvas);
if (mPageWidget.DragToRight()) {
//是否从左边翻向右边
try {
//true,显示上一页
pagefactory.prePage();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if(pagefactory.isfirstPage())return false;
pagefactory.onDraw(mNextPageCanvas);
} else {
try {
//false,显示下一页
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;
}
});
}
}
package com.zhang;
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;
/*
* 内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,
* 然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。
*
* fileChannel.map(FileChannel.MapMode mode, long position, long size)将此通道的文件区域直接映射到内存中。但是,你必
* 须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大
*/
FileChannel fc=new RandomAccessFile(book_file, "r").getChannel();
//文件通道的可读可写要建立在文件流本身可读写的基础之上
m_mbBuf =fc.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--;