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.      翻页效果

滑动翻页

用手指向左或者向右滑动,实现翻页。

Android文本翻页编码实现_第1张图片

方案一:

用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

 

你可能感兴趣的:(Android开发)