1.用MappedByteBuffer读取文本,MappedByteBuffer将文件直接映射到内存(这里的内存指的是虚拟内存,并不是物理内存,后面说证明这一点)。通常,可以映射整个文件,如果文件比较大的话可以分段进行映射,只要指定文件的那个部分就可以。具体可参照(http://blog.sina.com.cn/s/blog_679585110100tdcm.html)
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);
}
2.将文本转换成图片,如何确定一张图片可以容纳多少个字符。mPaint.breakText返回在宽度为mVisibleWidth的行中容纳的字符数。
int nSize = mPaint.breakText(strParagraph, true,mVisibleWidth,
null);
具体参考BookPageFactory.java,这个是网上一大牛写的,这一部分没有什么难度,代码也很清晰,看看源码就ok了。
1. 展示文本转换成的图片很简单,用ImageView或者自定义View中。
2. 翻页效果
用手指向左或者向右滑动,实现翻页。
方案一:
用PageView实现滑动翻页
try {
do {
mPageNum++;
Bitmap bmp = Bitmap.createBitmap(screenWidth,screenHeight,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
//将当前文本绘制成图片
pagefactory.onDraw(canvas);
View itemView =getLayoutInflater().inflate(R.layout.reader,
null);
ImageView reader = (ImageView)itemView
.findViewById(R.id.reader);
reader.setImageBitmap(bmp);
//将一张张转换后的图片加入到ViewPagerAdapter中
views.add(itemView);
} while (pagefactory.nextPage());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
vp = (ViewPager) findViewById(R.id.viewpager);
// 初始化Adapter
vpAdapter = new ViewPagerAdapter(views);
vp.setAdapter(vpAdapter);
// 绑定回调
vp.setOnPageChangeListener(this);
// overridePendingTransition(R.anim.tips_open, 0);
}
滑动翻页为ViewPage的自带功能实现,具体参考ReaderViewPageSimpleDemo.java源码.但是如果文本过大,一次加载,会使得ViewPagerAdapter中加载的图片太多,内存占用太大,可以优化,ViewPage一次加载到自己的容器中只有3个View,所以可以改写ViewPagerAdapter。我自己写了一个OptimizationViewPagerAdapter.java,如果大家有兴趣,可以自己写一个玩玩,感觉逻辑还是有点复杂,我是打印log调试了一会才知道instantiateItem和destroyItem调用时机,然后用循环队列实现,同时需要监听滑动方向,重绘下一张图片。
方案二:
用切割和组合原理重绘翻页,利用滑动的偏移,裁剪和组合当前图片和下一页图片。
public void moveBitmap(int offsetX,boolean isRighttoLeft) {
Print("offsetX:\t" + offsetX);
Canvas canvas = new Canvas(mMoveBitmap);
canvas.setDrawFilter(newPaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG));//消除锯齿
if (isRighttoLeft) {
//裁剪当前图片
canvas.drawBitmap(mCurPageBitmap,new Rect(-offsetX, 0,
screenWidth,screenHeight),new Rect(0, 0,screenWidth
+ offsetX, screenHeight),paint);
//裁剪下一页图片
canvas.drawBitmap(mNextPageBitmap,new Rect(0, 0,-offsetX,
screenHeight),new Rect(screenWidth + offsetX, 0,
screenWidth,screenHeight),paint);
} else {
canvas.drawBitmap(mCurPageBitmap,new Rect(0, 0,screenWidth
- offsetX, screenHeight),new Rect(offsetX, 0,screenWidth,
screenHeight),paint);
canvas.drawBitmap(mNextPageBitmap,new Rect(screenWidth - offsetX,
0, screenWidth,screenHeight),new Rect(0, 0, offsetX,
screenHeight),paint);
}
image.postInvalidate();//通知图片重绘,刷新图片
}
用切割和组合原理,如何绘制切图案。
贝塞尔曲线完成翻页效果绘制
直线BezierControl1-BezierContro2是直线mTouch-mCorner垂直平分线。
mMiddleX = (mTouch.x +mCornerX) / 2;
mMiddleY = (mTouch.y +mCornerY) / 2;
由相似三角形BezierControl1-mMiddle-tempA和mMiddle-mCorner-tempA得:
线段BezierControl1-tempA/ 线段mMiddle-tempA= 线段mMiddle-tempA/ 线段mCorner-tempA
mBezierControl1.x =mMiddleX - (mCornerY -mMiddleY)
* (mCornerY - mMiddleY) / (mCornerX - mMiddleX);
mBezierControl1.y =mCornerY;
同理:
mBezierControl2.x =mCornerX;
mBezierControl2.y =mMiddleY - (mCornerX -mMiddleX)
*(mCornerX - mMiddleX) / (mCornerY - mMiddleY);
直线BezierStart1-BezierStart2是直线mTouch-mCorner的1/4垂直平分线。
线段BezierStart1-BezierControl1 / 线段BezierControl1-mCorner=2 / 1
mBezierStart1.x =mBezierControl1.x - (mCornerX -mBezierControl1.x)
/ 2;
mBezierStart1.y =mCornerY;
同理:
mBezierStart2.x =mCornerX;
mBezierStart2.y =mBezierControl2.y - (mCornerY -mBezierControl2.y)
/2;
BezierEnd1是直线BezierStart1-BezierStart2和直线mTouch-BezierControl1的交点。
mBezierEnd1 = getCross(mTouch,mBezierControl1,mBezierStart1,
mBezierStart2);
BezierEnd2是直线BezierStart1-BezierStart2和直线mTouch-BezierControl2的交点。
mBezierEnd2 = getCross(mTouch,mBezierControl2,mBezierStart1,
mBezierStart2);
Beziervertex1是直线BezierStart1-BezierEnd1的中点和BezierControl1点的中点。
mBeziervertex1.x = (mBezierStart1.x + 2 *mBezierControl1.x +mBezierEnd1.x) / 4;
mBeziervertex1.y = (2 *mBezierControl1.y +mBezierStart1.y +mBezierEnd1.y) / 4;
Beziervertex2是直线BezierStart2-BezierEnd2的中点和BezierControl2点的中点。
mBeziervertex2.x = (mBezierStart2.x + 2 *mBezierControl2.x +mBezierEnd2.x) / 4;
mBeziervertex2.y = (2 *mBezierControl2.y +mBezierStart2.y +mBezierEnd2.y) / 4;
获取两直线交点:
public PointF getCross(PointF P1, PointF P2, PointF P3, PointFP4) {
PointF CrossP = new PointF();
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;
}
当前页背面和下一页,即黄色区域和蓝色区域为mPath0:
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.clipPath(mPath0, Region.Op.XOR)来剪裁绘制;
下一页,即蓝色区域为mPath1:
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();
阴影效果是绘制一矩形渐变色,然后旋转到对应位置,形成阴影。
drawCurrentBackArea绘制当前页背面图片,实现原理将当前图片关于一直线mBezierControl1-mBezierControl2对称形成。
对应矩阵为(具体参考http://blog.csdn.net/pathuang68/article/details/6991867,http://zensheno.blog.51cto.com/2712776/513652):
public void f(float x1,float y1,float x2,float y2,float[] matrix) {
float k = (y2 - y1) / (x2 - x1);
matrix[0] = (1 - k * k) / (1 + k * k);
matrix[1] = (2 * k) / (1 + k * k);
matrix[3] = (2 * k) / (1 + k * k);
matrix[4] = (k * k - 1) / (1 + k * k);
}
f(mBezierControl1.x,mBezierControl1.y,mBezierControl2.x,
mBezierControl2.y,mMatrixArray);
mMatrix.reset();
mMatrix.setValues(mMatrixArray);
mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y);
mMatrix.postTranslate(mBezierControl1.x,mBezierControl1.y);
canvas.drawBitmap(bitmap,mMatrix, mPaint);
源码下载:http://download.csdn.net/detail/ssuchange/5875987
参考:
翻转翻页效果主要参考大牛“何明桂的小窝”
Android实现书籍翻页效果----原理篇
http://blog.csdn.net/hmg25/article/details/6306479
Android实现书籍翻页效果----源码篇
http://blog.csdn.net/hmg25/article/details/6319664
Android实现书籍翻页效果----升级篇
http://blog.csdn.net/hmg25/article/details/6419694
Android实现书籍翻页效果---番外篇之光影效果
http://blog.csdn.net/hmg25/article/details/6366279
Android实现书籍翻页效果----完结篇
http://blog.csdn.net/hmg25/article/details/6342539