Android文本翻頁編碼實現
步驟一:讀取文本並且把文本轉換成圖片。
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
參考:
翻轉翻頁效果主要參考大牛“何明桂的小窩”
http://blog.csdn.net/hmg25/article/details/6306479
http://blog.csdn.net/hmg25/article/details/6319664
http://blog.csdn.net/hmg25/article/details/6419694
http://blog.csdn.net/hmg25/article/details/6366279
http://blog.csdn.net/hmg25/article/details/6342539