Android文本翻頁編碼實現

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/6991867http://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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章