2016-04-22 10:41:32 u013749540 阅读数 6973

http://blog.csdn.net/johnsonblog/article/details/7974312


效果


其中使用了贝赛尔曲线原理,关于贝赛尔曲线的知识,推荐大家看下http://blog.csdn.net/hmg25的博客

主函数

[java] view plain copy
  1. package com.zhang;  
  2.   
  3. import java.io.IOException;  
  4. import android.app.Activity;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.Canvas;  
  8. import android.os.Bundle;  
  9. import android.view.MotionEvent;  
  10. import android.view.View;  
  11. import android.view.View.OnTouchListener;  
  12. import android.view.Window;  
  13. import android.view.WindowManager;  
  14. import android.widget.Toast;  
  15.   
  16. public class TurnBook extends Activity {  
  17.     /** Called when the activity is first created. */  
  18.     private PageWidget mPageWidget;  
  19.     Bitmap mCurPageBitmap, mNextPageBitmap;  
  20.     Canvas mCurPageCanvas, mNextPageCanvas;  
  21.     BookPageFactory pagefactory;  
  22.   
  23.     @Override  
  24.     public void onCreate(Bundle savedInstanceState) {  
  25.         super.onCreate(savedInstanceState);  
  26.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  27.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
  28.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);  
  29.         mPageWidget = new PageWidget(this);  
  30.         setContentView(mPageWidget);  
  31.   
  32.         mCurPageBitmap = Bitmap.createBitmap(480800, Bitmap.Config.ARGB_8888);  
  33.         mNextPageBitmap = Bitmap  
  34.                 .createBitmap(480800, Bitmap.Config.ARGB_8888);  
  35.   
  36.         mCurPageCanvas = new Canvas(mCurPageBitmap);  
  37.         mNextPageCanvas = new Canvas(mNextPageBitmap);  
  38.         pagefactory = new BookPageFactory(480800);//设置分辨率为480*800  
  39.   
  40.         pagefactory.setBgBitmap(BitmapFactory.decodeResource(  
  41.                 this.getResources(), R.drawable.bg));//设置背景图片  
  42.         try {  
  43.             pagefactory.openbook("/sdcard/test.txt");//打开文件  
  44.             pagefactory.onDraw(mCurPageCanvas);//将文字绘于手机屏幕  
  45.             } catch (IOException e1) {  
  46.             // TODO Auto-generated catch block  
  47.             e1.printStackTrace();  
  48.             Toast.makeText(this"电子书不存在,请将《test.txt》放在SD卡根目录下",  
  49.                     Toast.LENGTH_SHORT).show();  
  50.         }  
  51.   
  52.         mPageWidget.setBitmaps(mCurPageBitmap, mCurPageBitmap);  
  53.   
  54.         mPageWidget.setOnTouchListener(new OnTouchListener() {  
  55.             @Override  
  56.             public boolean onTouch(View v, MotionEvent e) {  
  57.                 // TODO Auto-generated method stub  
  58.                   
  59.                 boolean ret=false;  
  60.                 if (v == mPageWidget) {  
  61.                     if (e.getAction() == MotionEvent.ACTION_DOWN) {  
  62.                         //停止动画。与forceFinished(boolean)相反,Scroller滚动到最终x与y位置时中止动画。             
  63.                         mPageWidget.abortAnimation();  
  64.                         //计算拖拽点对应的拖拽角  
  65.                         mPageWidget.calcCornerXY(e.getX(), e.getY());  
  66.                         //将文字绘于当前页  
  67.                         pagefactory.onDraw(mCurPageCanvas);  
  68.                         if (mPageWidget.DragToRight()) {  
  69.                             //是否从左边翻向右边  
  70.                             try {  
  71.                                 //true,显示上一页                      
  72.                                 pagefactory.prePage();  
  73.                             } catch (IOException e1) {  
  74.                                 // TODO Auto-generated catch block  
  75.                                 e1.printStackTrace();  
  76.                             }                         
  77.                             if(pagefactory.isfirstPage())return false;  
  78.                             pagefactory.onDraw(mNextPageCanvas);  
  79.                         } else {  
  80.                             try {  
  81.                                 //false,显示下一页                             
  82.                                 pagefactory.nextPage();  
  83.                             } catch (IOException e1) {  
  84.                                 // TODO Auto-generated catch block  
  85.                                 e1.printStackTrace();  
  86.                             }  
  87.                             if(pagefactory.islastPage())return false;  
  88.                             pagefactory.onDraw(mNextPageCanvas);  
  89.                         }  
  90.                         mPageWidget.setBitmaps(mCurPageBitmap, mNextPageBitmap);  
  91.                     }  
  92.                    
  93.                      ret = mPageWidget.doTouchEvent(e);  
  94.                     return ret;  
  95.                 }  
  96.                 return false;  
  97.             }  
  98.   
  99.         });  
  100.     }  
  101. }  



[java] view plain copy
  1. package com.zhang;  
  2. import java.io.File;  
  3. import java.io.IOException;  
  4. import java.io.RandomAccessFile;  
  5. import java.io.UnsupportedEncodingException;  
  6. import java.nio.MappedByteBuffer;  
  7. import java.nio.channels.FileChannel;  
  8. import java.text.DecimalFormat;  
  9. import java.util.Vector;  
  10.   
  11. import android.graphics.Bitmap;  
  12. import android.graphics.Canvas;  
  13. import android.graphics.Color;  
  14. import android.graphics.Paint;  
  15. import android.graphics.Paint.Align;  
  16.   
  17. public class BookPageFactory {  
  18.   
  19.     private File book_file = null;  
  20.     private MappedByteBuffer m_mbBuf = null;  
  21.     private int m_mbBufLen = 0;  
  22.     private int m_mbBufBegin = 0;  
  23.     private int m_mbBufEnd = 0;  
  24.     private String m_strCharsetName = "GBK";  
  25.     private Bitmap m_book_bg = null;  
  26.     private int mWidth;  
  27.     private int mHeight;  
  28.   
  29.     private Vector<String> m_lines = new Vector<String>();  
  30.   
  31.     private int m_fontSize = 24;  
  32.     private int m_textColor = Color.BLACK;  
  33.     private int m_backColor = 0xffff9e85// 背景颜色  
  34.     private int marginWidth = 15// 左右与边缘的距离  
  35.     private int marginHeight = 20// 上下与边缘的距离  
  36.     private int mLineCount; // 每页可以显示的行数  
  37.     private float mVisibleHeight; // 绘制内容的宽  
  38.     private float mVisibleWidth; // 绘制内容的宽  
  39.     private boolean m_isfirstPage,m_islastPage;  
  40.   
  41.     // private int m_nLineSpaceing = 5;  
  42.   
  43.     private Paint mPaint;  
  44.   
  45.     public BookPageFactory(int w, int h) {  
  46.         // TODO Auto-generated constructor stub  
  47.         mWidth = w;  
  48.         mHeight = h;  
  49.         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
  50.         mPaint.setTextAlign(Align.LEFT);//设置绘制文字的对齐方向    
  51.         mPaint.setTextSize(m_fontSize);  
  52.         mPaint.setColor(m_textColor);  
  53.         mVisibleWidth = mWidth - marginWidth * 2;  
  54.         mVisibleHeight = mHeight - marginHeight * 2;  
  55.         mLineCount = (int) (mVisibleHeight / m_fontSize); // 可显示的行数  
  56.     }  
  57.   
  58.     public void openbook(String strFilePath) throws IOException {  
  59.         book_file = new File(strFilePath);  
  60.         long lLen = book_file.length();  
  61.         m_mbBufLen = (int) lLen;  
  62.           
  63.         /* 
  64.          * 内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存, 
  65.          * 然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。  
  66.          *  
  67.         * fileChannel.map(FileChannel.MapMode mode, long position, long size)将此通道的文件区域直接映射到内存中。但是,你必 
  68.         * 须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大 
  69.         */  
  70.         FileChannel fc=new RandomAccessFile(book_file, "r").getChannel();  
  71.           
  72.         //文件通道的可读可写要建立在文件流本身可读写的基础之上    
  73.         m_mbBuf =fc.map(FileChannel.MapMode.READ_ONLY, 0, lLen);  
  74.     }  
  75.       
  76.   
  77.     protected byte[] readParagraphBack(int nFromPos) {  
  78.         int nEnd = nFromPos;  
  79.         int i;  
  80.         byte b0, b1;  
  81.         if (m_strCharsetName.equals("UTF-16LE")) {  
  82.             i = nEnd - 2;  
  83.             while (i > 0) {  
  84.                 b0 = m_mbBuf.get(i);  
  85.                 b1 = m_mbBuf.get(i + 1);  
  86.                 if (b0 == 0x0a && b1 == 0x00 && i != nEnd - 2) {  
  87.                     i += 2;  
  88.                     break;  
  89.                 }  
  90.                 i--;  
  91.             }  
  92.   
  93.         } else if (m_strCharsetName.equals("UTF-16BE")) {  
  94.             i = nEnd - 2;  
  95.             while (i > 0) {  
  96.                 b0 = m_mbBuf.get(i);  
  97.                 b1 = m_mbBuf.get(i + 1);  
  98.                 if (b0 == 0x00 && b1 == 0x0a && i != nEnd - 2) {  
  99.                     i += 2;  
  100.                     break;  
  101.                 }  
  102.                 i--;  
  103.             }  
  104.         } else {  
  105.             i = nEnd - 1;  
  106.             while (i > 0) {  
  107.                 b0 = m_mbBuf.get(i);  
  108.                 if (b0 == 0x0a && i != nEnd - 1) {  
  109.                     i++;  
  110.                     break;  
  111.                 }  
  112.                 i--;  
  113.             }  
  114.         }  
  115.         if (i < 0)  
  116.             i = 0;  
  117.         int nParaSize = nEnd - i;  
  118.         int j;  
  119.         byte[] buf = new byte[nParaSize];  
  120.         for (j = 0; j < nParaSize; j++) {  
  121.             buf[j] = m_mbBuf.get(i + j);  
  122.         }  
  123.         return buf;  
  124.     }  
  125.   
  126.   
  127.     //读取上一段落  
  128.     protected byte[] readParagraphForward(int nFromPos) {  
  129.         int nStart = nFromPos;  
  130.         int i = nStart;  
  131.         byte b0, b1;  
  132.         // 根据编码格式判断换行  
  133.         if (m_strCharsetName.equals("UTF-16LE")) {  
  134.             while (i < m_mbBufLen - 1) {  
  135.                 b0 = m_mbBuf.get(i++);  
  136.                 b1 = m_mbBuf.get(i++);  
  137.                 if (b0 == 0x0a && b1 == 0x00) {  
  138.                     break;  
  139.                 }  
  140.             }  
  141.         } else if (m_strCharsetName.equals("UTF-16BE")) {  
  142.             while (i < m_mbBufLen - 1) {  
  143.                 b0 = m_mbBuf.get(i++);  
  144.                 b1 = m_mbBuf.get(i++);  
  145.                 if (b0 == 0x00 && b1 == 0x0a) {  
  146.                     break;  
  147.                 }  
  148.             }  
  149.         } else {  
  150.             while (i < m_mbBufLen) {  
  151.                 b0 = m_mbBuf.get(i++);  
  152.                 if (b0 == 0x0a) {  
  153.                     break;  
  154.                 }  
  155.             }  
  156.         }  
  157.         //共读取了多少字符  
  158.         int nParaSize = i - nStart;  
  159.         byte[] buf = new byte[nParaSize];  
  160.         for (i = 0; i < nParaSize; i++) {  
  161.             //将已读取的字符放入数组  
  162.             buf[i] = m_mbBuf.get(nFromPos + i);  
  163.         }  
  164.         return buf;  
  165.     }  
  166.   
  167.     protected Vector<String> pageDown() {  
  168.         String strParagraph = "";  
  169.         Vector<String> lines = new Vector<String>();  
  170.         while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen) {  
  171.             byte[] paraBuf = readParagraphForward(m_mbBufEnd); // 读取一个段落  
  172.             m_mbBufEnd += paraBuf.length;//结束位置后移paraBuf.length  
  173.             try {  
  174.                 strParagraph = new String(paraBuf, m_strCharsetName);//通过decode指定的编码格式将byte[]转换为字符串           
  175.                 } catch (UnsupportedEncodingException e) {  
  176.                 // TODO Auto-generated catch block  
  177.                 e.printStackTrace();  
  178.             }  
  179.             String strReturn = "";  
  180.               
  181.             //去除将字符串中的特殊字符  
  182.             if (strParagraph.indexOf("\r\n") != -1) {  
  183.                 strReturn = "\r\n";  
  184.                 strParagraph = strParagraph.replaceAll("\r\n""");  
  185.             } else if (strParagraph.indexOf("\n") != -1) {  
  186.                 strReturn = "\n";  
  187.                 strParagraph = strParagraph.replaceAll("\n""");  
  188.             }  
  189.   
  190.             if (strParagraph.length() == 0) {  
  191.                 lines.add(strParagraph);  
  192.             }  
  193.             while (strParagraph.length() > 0) {  
  194.                 //计算每行可以显示多少个字符  
  195.                 //获益匪浅  
  196.                 int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth,null);  
  197.                 lines.add(strParagraph.substring(0, nSize));  
  198.                 strParagraph = strParagraph.substring(nSize);//截取从nSize开始的字符串  
  199.                 if (lines.size() >= mLineCount) {  
  200.                     break;  
  201.                 }  
  202.             }  
  203.             //当前页没显示完  
  204.             if (strParagraph.length() != 0) {  
  205.                 try {  
  206.                     m_mbBufEnd -= (strParagraph + strReturn)  
  207.                             .getBytes(m_strCharsetName).length;  
  208.                 } catch (UnsupportedEncodingException e) {  
  209.                     // TODO Auto-generated catch block  
  210.                     e.printStackTrace();  
  211.                 }  
  212.             }  
  213.         }  
  214.         return lines;  
  215.     }  
  216.   
  217.     protected void pageUp() {  
  218.         if (m_mbBufBegin < 0)  
  219.             m_mbBufBegin = 0;  
  220.         Vector<String> lines = new Vector<String>();  
  221.         String strParagraph = "";  
  222.         while (lines.size() < mLineCount && m_mbBufBegin > 0) {  
  223.             Vector<String> paraLines = new Vector<String>();  
  224.             byte[] paraBuf = readParagraphBack(m_mbBufBegin);  
  225.             m_mbBufBegin -= paraBuf.length;  
  226.             try {  
  227.                 strParagraph = new String(paraBuf, m_strCharsetName);  
  228.             } catch (UnsupportedEncodingException e) {  
  229.                 // TODO Auto-generated catch block  
  230.                 e.printStackTrace();  
  231.             }  
  232.             strParagraph = strParagraph.replaceAll("\r\n""");  
  233.             strParagraph = strParagraph.replaceAll("\n""");  
  234.   
  235.             if (strParagraph.length() == 0) {  
  236.                 paraLines.add(strParagraph);  
  237.             }  
  238.             while (strParagraph.length() > 0) {  
  239.                 int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth,  
  240.                         null);  
  241.                 paraLines.add(strParagraph.substring(0, nSize));  
  242.                 strParagraph = strParagraph.substring(nSize);  
  243.             }  
  244.             lines.addAll(0, paraLines);  
  245.         }  
  246.         while (lines.size() > mLineCount) {  
  247.             try {  
  248.                 m_mbBufBegin += lines.get(0).getBytes(m_strCharsetName).length;  
  249.                 lines.remove(0);  
  250.             } catch (UnsupportedEncodingException e) {  
  251.                 // TODO Auto-generated catch block  
  252.                 e.printStackTrace();  
  253.             }  
  254.         }  
  255.         m_mbBufEnd = m_mbBufBegin;  
  256.         return;  
  257.     }  
  258.   
  259.     protected void prePage() throws IOException {  
  260.         if (m_mbBufBegin <= 0) {  
  261.             //第一页  
  262.             m_mbBufBegin = 0;  
  263.             m_isfirstPage=true;  
  264.             return;  
  265.         }else m_isfirstPage=false;  
  266.         m_lines.clear();//Removes all elements from this vector, leaving it empty.  
  267.         pageUp();  
  268.         m_lines = pageDown();  
  269.     }  
  270.   
  271.     public void nextPage() throws IOException {  
  272.         if (m_mbBufEnd >= m_mbBufLen) {  
  273.             m_islastPage=true;  
  274.             return;  
  275.         }else m_islastPage=false;  
  276.         m_lines.clear();  
  277.         m_mbBufBegin = m_mbBufEnd;  
  278.         m_lines = pageDown();  
  279.     }  
  280.   
  281.     public void onDraw(Canvas c) {  
  282.         if (m_lines.size() == 0)  
  283.             m_lines = pageDown();  
  284.         if (m_lines.size() > 0) {  
  285.             if (m_book_bg == null)  
  286.                 c.drawColor(m_backColor);  
  287.             else  
  288.                 c.drawBitmap(m_book_bg, 00null);  
  289.             int y = marginHeight;  
  290.             for (String strLine : m_lines) {  
  291.                 y += m_fontSize;  
  292.                 //从(x,y)坐标将文字绘于手机屏幕       
  293.                 c.drawText(strLine, marginWidth, y, mPaint);  
  294.             }  
  295.         }  
  296.         //计算百分比(不包括当前页)并格式化  
  297.         float fPercent = (float) (m_mbBufBegin * 1.0 / m_mbBufLen);  
  298.         DecimalFormat df = new DecimalFormat("#0.0");  
  299.         String strPercent = df.format(fPercent * 100) + "%";  
  300.           
  301.         //计算999.9%所占的像素宽度     
  302.         int nPercentWidth = (int) mPaint.measureText("999.9%") + 1;  
  303.         c.drawText(strPercent, mWidth - nPercentWidth, mHeight - 5, mPaint);  
  304.     }  
  305.   
  306.     public void setBgBitmap(Bitmap BG) {  
  307.         m_book_bg = BG;  
  308.     }  
  309.       
  310.     public boolean isfirstPage() {  
  311.         return m_isfirstPage;  
  312.     }  
  313.     public boolean islastPage() {  
  314.         return m_islastPage;  
  315.     }  
  316. }  



[java] view plain copy
  1. package com.zhang;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.ColorMatrix;  
  7. import android.graphics.ColorMatrixColorFilter;  
  8. import android.graphics.Matrix;  
  9. import android.graphics.Paint;  
  10. import android.graphics.Path;  
  11. import android.graphics.PointF;  
  12. import android.graphics.Region;  
  13. import android.graphics.drawable.GradientDrawable;  
  14. import android.view.MotionEvent;  
  15. import android.view.View;  
  16. import android.widget.Scroller;  
  17.   
  18. public class PageWidget extends View {  
  19.   
  20.     private static final String TAG = "Book_Turn";  
  21.     private int mWidth = 480;  
  22.     private int mHeight = 800;  
  23.     private int mCornerX = 0// 拖拽点对应的页脚  
  24.     private int mCornerY = 0;  
  25.     private Path mPath0;  
  26.     private Path mPath1;  
  27.     Bitmap mCurPageBitmap = null// 当前页  
  28.     Bitmap mNextPageBitmap = null;  
  29.       
  30.     //PointF:PointF holds two float coordinates  
  31.     PointF mTouch = new PointF(); // // 拖拽点  
  32.     PointF mBezierStart1 = new PointF(); // 贝塞尔曲线起始点  
  33.     PointF mBezierControl1 = new PointF(); // 贝塞尔曲线控制点  
  34.     PointF mBeziervertex1 = new PointF(); // 贝塞尔曲线顶点  
  35.     PointF mBezierEnd1 = new PointF(); // 贝塞尔曲线结束点  
  36.   
  37.     PointF mBezierStart2 = new PointF(); // 另一条贝塞尔曲线  
  38.     PointF mBezierControl2 = new PointF();  
  39.     PointF mBeziervertex2 = new PointF();  
  40.     PointF mBezierEnd2 = new PointF();  
  41.   
  42.     float mMiddleX;  
  43.     float mMiddleY;  
  44.     float mDegrees;  
  45.     float mTouchToCornerDis;  
  46.     ColorMatrixColorFilter mColorMatrixFilter;  
  47.     Matrix mMatrix;  
  48.     float[] mMatrixArray = { 000000001.0f };  
  49.   
  50.     boolean mIsRTandLB; // 是否属于右上左下  
  51.     float mMaxLength = (float) Math.hypot(mWidth, mHeight);  
  52.     int[] mBackShadowColors;  
  53.     int[] mFrontShadowColors;  
  54.     GradientDrawable mBackShadowDrawableLR;  
  55.     GradientDrawable mBackShadowDrawableRL;  
  56.     GradientDrawable mFolderShadowDrawableLR;  
  57.     GradientDrawable mFolderShadowDrawableRL;  
  58.   
  59.     GradientDrawable mFrontShadowDrawableHBT;  
  60.     GradientDrawable mFrontShadowDrawableHTB;  
  61.     GradientDrawable mFrontShadowDrawableVLR;  
  62.     GradientDrawable mFrontShadowDrawableVRL;  
  63.   
  64.     Paint mPaint;  
  65.   
  66.     Scroller mScroller;  
  67.   
  68.     public PageWidget(Context context) {  
  69.         super(context);  
  70.         // TODO Auto-generated constructor stub  
  71.         /**    
  72.          * Paint类介绍    
  73.          *     
  74.          * Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色,    
  75.          * 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,    
  76.          * 大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。           
  77.          *     
  78.          * 1.图形绘制    
  79.          * setARGB(int a,int r,int g,int b);    
  80.          * 设置绘制的颜色,a代表透明度,r,g,b代表颜色值。    
  81.          *     
  82.          * setAlpha(int a);    
  83.          * 设置绘制图形的透明度。    
  84.          *     
  85.          * setColor(int color);    
  86.          * 设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。    
  87.          *     
  88.         * setAntiAlias(boolean aa);    
  89.          * 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。    
  90.          *     
  91.          * setDither(boolean dither);    
  92.          * 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰    
  93.          *     
  94.          * setFilterBitmap(boolean filter);    
  95.          * 如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作,加快显示    
  96.          * 速度,本设置项依赖于dither和xfermode的设置    
  97.          *     
  98.          * setMaskFilter(MaskFilter maskfilter);    
  99.          * 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等       *     
  100.          * setColorFilter(ColorFilter colorfilter);    
  101.          * 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果    
  102.          *     
  103.          * setPathEffect(PathEffect effect);    
  104.          * 设置绘制路径的效果,如点画线等    
  105.          *     
  106.          * setShader(Shader shader);    
  107.          * 设置图像效果,使用Shader可以绘制出各种渐变效果    
  108.          *    
  109.          * setShadowLayer(float radius ,float dx,float dy,int color);    
  110.          * 在图形下面设置阴影层,产生阴影效果,radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色    
  111.          *     
  112.          * setStyle(Paint.Style style);    
  113.          * 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE    
  114.          *     
  115.          * setStrokeCap(Paint.Cap cap);    
  116.          * 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式,如圆形样式    
  117.          * Cap.ROUND,或方形样式Cap.SQUARE    
  118.          *     
  119.          * setSrokeJoin(Paint.Join join);    
  120.          * 设置绘制时各图形的结合方式,如平滑效果等    
  121.          *     
  122.          * setStrokeWidth(float width);    
  123.          * 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度    
  124.          *     
  125.          * setXfermode(Xfermode xfermode);    
  126.          * 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果    
  127.          *     
  128.          * 2.文本绘制    
  129.          * setFakeBoldText(boolean fakeBoldText);    
  130.          * 模拟实现粗体文字,设置在小字体上效果会非常差    
  131.          *     
  132.          * setSubpixelText(boolean subpixelText);    
  133.          * 设置该项为true,将有助于文本在LCD屏幕上的显示效果    
  134.          *        
  135.        * setTextScaleX(float scaleX);    
  136.         * 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果    
  137.          *     
  138.          * setTextSkewX(float skewX);    
  139.          * 设置斜体文字,skewX为倾斜弧度    
  140.          *     
  141.          * setTypeface(Typeface typeface);    
  142.          * 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等    
  143.          *     
  144.          * setUnderlineText(boolean underlineText);    
  145.          * 设置带有下划线的文字效果    
  146.          *     
  147.          * setStrikeThruText(boolean strikeThruText);    
  148.          * 设置带有删除线的效果    
  149.          *     
  150.          */      
  151.         mPath0 = new Path();//Path路径对象   
  152.         mPath1 = new Path();  
  153.         createDrawable();  
  154.   
  155.         mPaint = new Paint();  
  156.         mPaint.setStyle(Paint.Style.FILL);  
  157.   
  158.         //颜色矩阵(ColorMatrix)和坐标变换矩阵(Matrix),对图片进行变换,以拉伸,扭曲等  
  159.         ColorMatrix cm = new ColorMatrix();  
  160.           
  161.         //颜色矩阵,颜色矩阵是一个5x4 的矩阵,可以用来方便的修改图片中RGBA各分量的值,颜色矩阵以一维数组的方式存储如下:  
  162.         // [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ],他通过RGBA四个通道来直接操作对应颜色  
  163.         float array[] = { 0.55f, 00080.0f, 00.55f, 0080.0f, 00,  
  164.                 0.55f, 080.0f, 0000.2f, 0 };  
  165.         cm.set(array);  
  166.         //颜色滤镜,就像QQ的在线和离线图片,同一张图片通过颜色滤镜处理,显示不同的效果,可减少图片资源  
  167.         mColorMatrixFilter = new ColorMatrixColorFilter(cm);  
  168.         mMatrix = new Matrix();  
  169.         mScroller = new Scroller(getContext());  
  170.   
  171.         mTouch.x = 0.01f; // 不让x,y为0,否则在点计算时会有问题  
  172.         mTouch.y = 0.01f;  
  173.     }  
  174.   
  175.     /** 
  176.      * 计算拖拽点对应的拖拽角 
  177.      */  
  178.     public void calcCornerXY(float x, float y) {  
  179.         //将手机屏幕分为四个象限,判断手指落在哪个象限内  
  180.         if (x <= mWidth / 2)  
  181.             mCornerX = 0;  
  182.         else  
  183.             mCornerX = mWidth;  
  184.         if (y <= mHeight / 2)  
  185.             mCornerY = 0;  
  186.         else  
  187.             mCornerY = mHeight;  
  188.           
  189.         //如果手指落在第一象限或第三象限,也就是右上角或左下角  
  190.         if ((mCornerX == 0 && mCornerY == mHeight)  
  191.                 || (mCornerX == mWidth && mCornerY == 0))  
  192.             mIsRTandLB = true;  
  193.         else  
  194.             mIsRTandLB = false;  
  195.     }  
  196.   
  197.     public boolean doTouchEvent(MotionEvent event) {  
  198.         // TODO Auto-generated method stub  
  199.         if (event.getAction() == MotionEvent.ACTION_MOVE) {  
  200.             mTouch.x = event.getX();  
  201.             mTouch.y = event.getY();  
  202.             /* Android提供了Invalidate和postInvalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型: 
  203.              * Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。  
  204.              * invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉 
  205.              * 而postInvalidate()在工作者线程中被调用 
  206.             */  
  207.             this.postInvalidate();  
  208.         }  
  209.         if (event.getAction() == MotionEvent.ACTION_DOWN) {  
  210.             mTouch.x = event.getX();  
  211.             mTouch.y = event.getY();  
  212.             // calcCornerXY(mTouch.x, mTouch.y);  
  213.             // this.postInvalidate();  
  214.         }  
  215.         if (event.getAction() == MotionEvent.ACTION_UP) {  
  216.             //是否触发翻页  
  217.             if (canDragOver()) {  
  218.                 startAnimation(1200);  
  219.             } else {  
  220.                 mTouch.x = mCornerX - 0.09f;//如果不能翻页就让mTouch返回没有静止时的状态  
  221.                 mTouch.y = mCornerY - 0.09f;//- 0.09f是防止mTouch = 800 或mTouch= 0 ,在这些值时会出现BUG  
  222.             }  
  223.   
  224.             this.postInvalidate();  
  225.         }  
  226.         // return super.onTouchEvent(event);  
  227.         return true;  
  228.     }  
  229.   
  230.     /** 
  231.      * 求解直线P1P2和直线P3P4的交点坐标 
  232.      */  
  233.     public PointF getCross(PointF P1, PointF P2, PointF P3, PointF P4) {  
  234.         PointF CrossP = new PointF();  
  235.         // 二元函数通式: y=ax+b  
  236.         float a1 = (P2.y - P1.y) / (P2.x - P1.x);  
  237.         float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x);  
  238.   
  239.         float a2 = (P4.y - P3.y) / (P4.x - P3.x);  
  240.         float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x);  
  241.         CrossP.x = (b2 - b1) / (a1 - a2);  
  242.         CrossP.y = a1 * CrossP.x + b1;  
  243.         return CrossP;  
  244.     }  
  245.   
  246.     private void calcPoints() {  
  247.         mMiddleX = (mTouch.x + mCornerX) / 2;  
  248.         mMiddleY = (mTouch.y + mCornerY) / 2;  
  249.         mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)  
  250.                 * (mCornerY - mMiddleY) / (mCornerX - mMiddleX);  
  251.         mBezierControl1.y = mCornerY;  
  252.         mBezierControl2.x = mCornerX;  
  253.         mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)  
  254.                 * (mCornerX - mMiddleX) / (mCornerY - mMiddleY);  
  255.   
  256.         mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x)  
  257.                 / 2;  
  258.         mBezierStart1.y = mCornerY;  
  259.   
  260.         // 当mBezierStart1.x < 0或者mBezierStart1.x > 480时  
  261.                 // 如果继续翻页,会出现BUG故在此限制  
  262.         if (mTouch.x > 0 && mTouch.x < mWidth) {  
  263.             if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth) {  
  264.                 if (mBezierStart1.x < 0)  
  265.                     mBezierStart1.x = mWidth - mBezierStart1.x;  
  266.   
  267.                 float f1 = Math.abs(mCornerX - mTouch.x);  
  268.                 float f2 = mWidth * f1 / mBezierStart1.x;  
  269.                 mTouch.x = Math.abs(mCornerX - f2);  
  270.   
  271.                 float f3 = Math.abs(mCornerX - mTouch.x)  
  272.                         * Math.abs(mCornerY - mTouch.y) / f1;  
  273.                 mTouch.y = Math.abs(mCornerY - f3);  
  274.   
  275.                 mMiddleX = (mTouch.x + mCornerX) / 2;  
  276.                 mMiddleY = (mTouch.y + mCornerY) / 2;  
  277.   
  278.                 mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)  
  279.                         * (mCornerY - mMiddleY) / (mCornerX - mMiddleX);  
  280.                 mBezierControl1.y = mCornerY;  
  281.   
  282.                 mBezierControl2.x = mCornerX;  
  283.                 mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)  
  284.                         * (mCornerX - mMiddleX) / (mCornerY - mMiddleY);  
  285.       
  286.                 mBezierStart1.x = mBezierControl1.x  
  287.                         - (mCornerX - mBezierControl1.x) / 2;  
  288.             }  
  289.         }  
  290.         mBezierStart2.x = mCornerX;  
  291.         mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y)  
  292.                 / 2;  
  293.   
  294.         mTouchToCornerDis = (float) Math.hypot((mTouch.x - mCornerX),  
  295.                 (mTouch.y - mCornerY));  
  296.   
  297.         mBezierEnd1 = getCross(mTouch, mBezierControl1, mBezierStart1,  
  298.                 mBezierStart2);  
  299.         mBezierEnd2 = getCross(mTouch, mBezierControl2, mBezierStart1,  
  300.                 mBezierStart2);  
  301.   
  302.         /* 
  303.          * mBeziervertex1.x 推导 
  304.          * ((mBezierStart1.x+mBezierEnd1.x)/2+mBezierControl1.x)/2 化简等价于 
  305.          * (mBezierStart1.x+ 2*mBezierControl1.x+mBezierEnd1.x) / 4 
  306.          */  
  307.         mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4;  
  308.         mBeziervertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4;  
  309.         mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4;  
  310.         mBeziervertex2.y = (2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4;  
  311.     }  
  312.   
  313.     private void drawCurrentPageArea(Canvas canvas, Bitmap bitmap, Path path) {  
  314.         mPath0.reset();  
  315.         mPath0.moveTo(mBezierStart1.x, mBezierStart1.y);  
  316.         mPath0.quadTo(mBezierControl1.x, mBezierControl1.y, mBezierEnd1.x,  
  317.                 mBezierEnd1.y);  
  318.         mPath0.lineTo(mTouch.x, mTouch.y);  
  319.         mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y);  
  320.         mPath0.quadTo(mBezierControl2.x, mBezierControl2.y, mBezierStart2.x,  
  321.                 mBezierStart2.y);  
  322.         mPath0.lineTo(mCornerX, mCornerY);  
  323.         mPath0.close();  
  324.   
  325.         canvas.save();  
  326.         canvas.clipPath(path, Region.Op.XOR);  
  327.         canvas.drawBitmap(bitmap, 00null);  
  328.         canvas.restore();  
  329.     }  
  330.   
  331.     private void drawNextPageAreaAndShadow(Canvas canvas, Bitmap bitmap) {  
  332.         mPath1.reset();  
  333.         mPath1.moveTo(mBezierStart1.x, mBezierStart1.y);  
  334.         mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y);  
  335.         mPath1.lineTo(mBeziervertex2.x, mBeziervertex2.y);  
  336.         mPath1.lineTo(mBezierStart2.x, mBezierStart2.y);  
  337.         mPath1.lineTo(mCornerX, mCornerY);  
  338.         mPath1.close();  
  339.   
  340.         mDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl1.x  
  341.                 - mCornerX, mBezierControl2.y - mCornerY));  
  342.         int leftx;  
  343.         int rightx;  
  344.         GradientDrawable mBackShadowDrawable;  
  345.         if (mIsRTandLB) {  
  346.             leftx = (int) (mBezierStart1.x);  
  347.             rightx = (int) (mBezierStart1.x + mTouchToCornerDis / 4);  
  348.             mBackShadowDrawable = mBackShadowDrawableLR;  
  349.         } else {  
  350.             leftx = (int) (mBezierStart1.x - mTouchToCornerDis / 4);  
  351.             rightx = (int) mBezierStart1.x;  
  352.             mBackShadowDrawable = mBackShadowDrawableRL;  
  353.         }  
  354.         canvas.save();  
  355.         canvas.clipPath(mPath0);  
  356.         canvas.clipPath(mPath1, Region.Op.INTERSECT);  
  357.         canvas.drawBitmap(bitmap, 00null);  
  358.         canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y);  
  359.         mBackShadowDrawable.setBounds(leftx, (int) mBezierStart1.y, rightx,  
  360.                 (int) (mMaxLength + mBezierStart1.y));  
  361.         mBackShadowDrawable.draw(canvas);  
  362.         canvas.restore();  
  363.     }  
  364.   
  365.     public void setBitmaps(Bitmap bm1, Bitmap bm2) {  
  366.         mCurPageBitmap = bm1;  
  367.         mNextPageBitmap = bm2;  
  368.     }  
  369.   
  370.     public void setScreen(int w, int h) {  
  371.         mWidth = w;  
  372.         mHeight = h;  
  373.     }  
  374.   
  375.     @Override  
  376.     protected void onDraw(Canvas canvas) {  
  377.         canvas.drawColor(0xFFAAAAAA);  
  378.         calcPoints();  
  379.         drawCurrentPageArea(canvas, mCurPageBitmap, mPath0);  
  380.         drawNextPageAreaAndShadow(canvas, mNextPageBitmap);  
  381.         drawCurrentPageShadow(canvas);  
  382.         drawCurrentBackArea(canvas, mCurPageBitmap);  
  383.     }  
  384.   
  385.     /** 
  386.      * 创建阴影的GradientDrawable 
  387.      */  
  388.     private void createDrawable() {  
  389.           
  390.         /* 
  391.          * GradientDrawable 支持使用渐变色来绘制图形,通常可以用作Button或是背景图形。 
  392.  
  393.         * GradientDrawable允许指定绘制图形的种类:LINE,OVAL,RECTANGLE或是RING ,颜色渐变支持LINEAR_GRADIENT,RADIAL_GRADIENT 和 SWEEP_GRADIENT。 
  394.  
  395.         * 其中在使用RECTANGLE(矩形),还允许设置矩形四个角为圆角,每个圆角的半径可以分别设置: 
  396.  
  397.         * public void setCornerRadii(float[] radii) 
  398.  
  399.         * radii 数组分别指定四个圆角的半径,每个角可以指定[X_Radius,Y_Radius],四个圆角的顺序为左上,右上,右下,左下。如果X_Radius,Y_Radius为0表示还是直角。 
  400.  
  401.         * 颜色渐变的方向由GradientDrawable.Orientation定义,共八种 
  402.          
  403.         * GradientDrawable的构造函数:public GradientDrawable(GradientDrawable.Orientation orientation, int[] colors) 
  404.  
  405.         * orientation指定了渐变的方向,渐变的颜色由colors数组指定,数组中的每个值为一个颜色。 
  406.  
  407.         * 本例定义一个渐变方向从组左上到右下,渐变颜色为红,绿,蓝三色: 
  408.          
  409.         * mDrawable = new GradientDrawable(GradientDrawable.Orientation.TL_BR,new int[] { 0xFFFF0000, 0xFF00FF00,0xFF0000FF }); 
  410.          
  411.         * 分别使用Liner,Radial 和Sweep三种渐变模式,并可配合指定矩形四个角圆角半径 
  412.         * */  
  413.           
  414.         int[] color = { 0x3333330x333333 };  
  415.           
  416.         //从右向左由颜色0x333333渐变为0x333333  
  417.         mFolderShadowDrawableRL = new GradientDrawable(  
  418.                 GradientDrawable.Orientation.RIGHT_LEFT, color);  
  419.         mFolderShadowDrawableRL  
  420.                 .setGradientType(GradientDrawable.LINEAR_GRADIENT);//线性渐变, "radial":径向渐变,  "sweep" :角度渐变  
  421.           
  422.         mFolderShadowDrawableLR = new GradientDrawable(  
  423.                 GradientDrawable.Orientation.LEFT_RIGHT, color);  
  424.         mFolderShadowDrawableLR  
  425.                 .setGradientType(GradientDrawable.LINEAR_GRADIENT);  
  426.   
  427.         mBackShadowColors = new int[] { 0xff1111110x111111 };  
  428.         mBackShadowDrawableRL = new GradientDrawable(  
  429.                 GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors);  
  430.         mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);  
  431.   
  432.         mBackShadowDrawableLR = new GradientDrawable(  
  433.                 GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors);  
  434.         mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);  
  435.   
  436.         mFrontShadowColors = new int[] { 0x801111110x111111 };  
  437.         mFrontShadowDrawableVLR = new GradientDrawable(  
  438.                 GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors);  
  439.         mFrontShadowDrawableVLR  
  440.                 .setGradientType(GradientDrawable.LINEAR_GRADIENT);  
  441.         mFrontShadowDrawableVRL = new GradientDrawable(  
  442.                 GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors);  
  443.         mFrontShadowDrawableVRL  
  444.                 .setGradientType(GradientDrawable.LINEAR_GRADIENT);  
  445.   
  446.         mFrontShadowDrawableHTB = new GradientDrawable(  
  447.                 GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors);  
  448.         mFrontShadowDrawableHTB  
  449.                 .setGradientType(GradientDrawable.LINEAR_GRADIENT);  
  450.   
  451.         mFrontShadowDrawableHBT = new GradientDrawable(  
  452.                 GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors);  
  453.         mFrontShadowDrawableHBT  
  454.                 .setGradientType(GradientDrawable.LINEAR_GRADIENT);  
  455.     }  
  456.   
  457.     /** 
  458.      * 绘制翻起页的阴影 
  459.      */  
  460.     public void drawCurrentPageShadow(Canvas canvas) {  
  461.         double degree;  
  462.         //计算两点间连线的倾斜角.  
  463.         //还可旋转饼图  
  464.         if (mIsRTandLB) {  
  465.             degree = Math.PI  
  466.                     / 4  
  467.                     - Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x  
  468.                             - mBezierControl1.x);  
  469.         } else {  
  470.             degree = Math.PI  
  471.                     / 4  
  472.                     - Math.atan2(mTouch.y - mBezierControl1.y, mTouch.x  
  473.                             - mBezierControl1.x);  
  474.         }  
  475.         // 翻起页阴影顶点与touch点的距离  
  476.         double d1 = (float25 * 1.414 * Math.cos(degree);  
  477.         double d2 = (float25 * 1.414 * Math.sin(degree);  
  478.         float x = (float) (mTouch.x + d1);  
  479.         float y;  
  480.         if (mIsRTandLB) {  
  481.             y = (float) (mTouch.y + d2);  
  482.         } else {  
  483.             y = (float) (mTouch.y - d2);  
  484.         }  
  485.         mPath1.reset();  
  486.         mPath1.moveTo(x, y);  
  487.         mPath1.lineTo(mTouch.x, mTouch.y);  
  488.         mPath1.lineTo(mBezierControl1.x, mBezierControl1.y);  
  489.         mPath1.lineTo(mBezierStart1.x, mBezierStart1.y);  
  490.         mPath1.close();  
  491.         float rotateDegrees;  
  492.         canvas.save();  
  493.   
  494.         canvas.clipPath(mPath0, Region.Op.XOR);  
  495.         canvas.clipPath(mPath1, Region.Op.INTERSECT);  
  496.         int leftx;  
  497.         int rightx;  
  498.         GradientDrawable mCurrentPageShadow;  
  499.         if (mIsRTandLB) {  
  500.             leftx = (int) (mBezierControl1.x);  
  501.             rightx = (int) mBezierControl1.x + 25;  
  502.             mCurrentPageShadow = mFrontShadowDrawableVLR;  
  503.         } else {  
  504.             leftx = (int) (mBezierControl1.x - 25);  
  505.             rightx = (int) mBezierControl1.x + 1;  
  506.             mCurrentPageShadow = mFrontShadowDrawableVRL;  
  507.         }  
  508.   
  509.         rotateDegrees = (float) Math.toDegrees(Math.atan2(mTouch.x  
  510.                 - mBezierControl1.x, mBezierControl1.y - mTouch.y));  
  511.         canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y);  
  512.         mCurrentPageShadow.setBounds(leftx,  
  513.                 (int) (mBezierControl1.y - mMaxLength), rightx,  
  514.                 (int) (mBezierControl1.y));  
  515.         mCurrentPageShadow.draw(canvas);  
  516.         canvas.restore();  
  517.   
  518.         mPath1.reset();  
  519.         mPath1.moveTo(x, y);  
  520.         mPath1.lineTo(mTouch.x, mTouch.y);  
  521.         mPath1.lineTo(mBezierControl2.x, mBezierControl2.y);  
  522.         mPath1.lineTo(mBezierStart2.x, mBezierStart2.y);  
  523.         mPath1.close();  
  524.         canvas.save();  
  525.         canvas.clipPath(mPath0, Region.Op.XOR);  
  526.         canvas.clipPath(mPath1, Region.Op.INTERSECT);  
  527.         if (mIsRTandLB) {  
  528.             leftx = (int) (mBezierControl2.y);  
  529.             rightx = (int) (mBezierControl2.y + 25);  
  530.             mCurrentPageShadow = mFrontShadowDrawableHTB;  
  531.         } else {  
  532.             leftx = (int) (mBezierControl2.y - 25);  
  533.             rightx = (int) (mBezierControl2.y + 1);  
  534.             mCurrentPageShadow = mFrontShadowDrawableHBT;  
  535.         }  
  536.         rotateDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl2.y  
  537.                 - mTouch.y, mBezierControl2.x - mTouch.x));  
  538.         canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y);  
  539.         float temp;  
  540.         if (mBezierControl2.y < 0)  
  541.             temp = mBezierControl2.y - mHeight;  
  542.         else  
  543.             temp = mBezierControl2.y;  
  544.   
  545.         int hmg = (int) Math.hypot(mBezierControl2.x, temp);  
  546.         if (hmg > mMaxLength)  
  547.             mCurrentPageShadow  
  548.                     .setBounds((int) (mBezierControl2.x - 25) - hmg, leftx,  
  549.                             (int) (mBezierControl2.x + mMaxLength) - hmg,  
  550.                             rightx);  
  551.         else  
  552.             mCurrentPageShadow.setBounds(  
  553.                     (int) (mBezierControl2.x - mMaxLength), leftx,  
  554.                     (int) (mBezierControl2.x), rightx);  
  555.   
  556.         mCurrentPageShadow.draw(canvas);  
  557.         canvas.restore();  
  558.     }  
  559.   
  560.     /** 
  561.      * 绘制翻起页背面 
  562.      */  
  563.     private void drawCurrentBackArea(Canvas canvas, Bitmap bitmap) {  
  564.         int i = (int) (mBezierStart1.x + mBezierControl1.x) / 2;  
  565.         float f1 = Math.abs(i - mBezierControl1.x);  
  566.         int i1 = (int) (mBezierStart2.y + mBezierControl2.y) / 2;  
  567.         float f2 = Math.abs(i1 - mBezierControl2.y);  
  568.         float f3 = Math.min(f1, f2);  
  569.         mPath1.reset();  
  570.         mPath1.moveTo(mBeziervertex2.x, mBeziervertex2.y);  
  571.         mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y);  
  572.         mPath1.lineTo(mBezierEnd1.x, mBezierEnd1.y);  
  573.         mPath1.lineTo(mTouch.x, mTouch.y);  
  574.         mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y);  
  575.         mPath1.close();  
  576.         GradientDrawable mFolderShadowDrawable;  
  577.         int left;  
  578.         int right;  
  579.         if (mIsRTandLB) {  
  580.             left = (int) (mBezierStart1.x - 1);  
  581.             right = (int) (mBezierStart1.x + f3 + 1);  
  582.             mFolderShadowDrawable = mFolderShadowDrawableLR;  
  583.         } else {  
  584.             left = (int) (mBezierStart1.x - f3 - 1);  
  585.             right = (int) (mBezierStart1.x + 1);  
  586.             mFolderShadowDrawable = mFolderShadowDrawableRL;  
  587.         }  
  588.         canvas.save();  
  589.         canvas.clipPath(mPath0);  
  590.         canvas.clipPath(mPath1, Region.Op.INTERSECT);  
  591.   
  592.         mPaint.setColorFilter(mColorMatrixFilter);  
  593.   
  594.         float dis = (float) Math.hypot(mCornerX - mBezierControl1.x,  
  595.                 mBezierControl2.y - mCornerY);  
  596.         float f8 = (mCornerX - mBezierControl1.x) / dis;  
  597.         float f9 = (mBezierControl2.y - mCornerY) / dis;  
  598.         mMatrixArray[0] = 1 - 2 * f9 * f9;  
  599.         mMatrixArray[1] = 2 * f8 * f9;  
  600.         mMatrixArray[3] = mMatrixArray[1];  
  601.         mMatrixArray[4] = 1 - 2 * f8 * f8;  
  602.         mMatrix.reset();  
  603.         mMatrix.setValues(mMatrixArray);  
  604.         mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y);  
  605.         mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y);  
  606.         canvas.drawBitmap(bitmap, mMatrix, mPaint);  
  607.         // canvas.drawBitmap(bitmap, mMatrix, null);  
  608.         mPaint.setColorFilter(null);  
  609.         canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y);  
  610.         mFolderShadowDrawable.setBounds(left, (int) mBezierStart1.y, right,  
  611.                 (int) (mBezierStart1.y + mMaxLength));  
  612.         mFolderShadowDrawable.draw(canvas);  
  613.         canvas.restore();  
  614.     }  
  615.   
  616.     public void computeScroll() {  
  617.         super.computeScroll();  
  618.         if (mScroller.computeScrollOffset()) {  
  619.             float x = mScroller.getCurrX();  
  620.             float y = mScroller.getCurrY();  
  621.             mTouch.x = x;  
  622.             mTouch.y = y;  
  623.             postInvalidate();  
  624.         }  
  625.     }  
  626.   
  627.     private void startAnimation(int delayMillis) {  
  628.         int dx, dy;  
  629.         // dx 水平方向滑动的距离,负值会使滚动向左滚动  
  630.         // dy 垂直方向滑动的距离,负值会使滚动向上滚动  
  631.         if (mCornerX > 0) {  
  632.             dx = -(int) (mWidth + mTouch.x);  
  633.         } else {  
  634.             dx = (int) (mWidth - mTouch.x + mWidth);  
  635.         }  
  636.         if (mCornerY > 0) {  
  637.             dy = (int) (mHeight - mTouch.y);  
  638.         } else {  
  639.             dy = (int) (1 - mTouch.y); // // 防止mTouch.y最终变为0  
  640.         }  
  641.         //Start scrolling by providing a starting point and the distance to travel.  
  642.         mScroller.startScroll((int) mTouch.x, (int) mTouch.y, dx, dy,  
  643.                 delayMillis);  
  644.     }  
  645.   
  646.     public void abortAnimation() {  
  647.         if (!mScroller.isFinished()) {  
  648.             //停止动画,与forceFinished(boolean)相反,Scroller滚动到最终x与y位置时中止动画。  
  649.             mScroller.abortAnimation();  
  650.         }  
  651.     }  
  652.   
  653.     public boolean canDragOver() {  
  654.         //设置开始翻页的条件  
  655. //      if (mTouchToCornerDis > mWidth / 10)  
  656.             if (mTouchToCornerDis>1)  
  657.             return true;  
  658.         return false;  
  659.     }  
  660.   
  661.     /** 
  662.      * 是否从左边翻向右边 
  663.      */  
  664.     public boolean DragToRight() {  
  665.         if (mCornerX > 0)  
  666.             return false;  
  667.         return true;  
  668.     }  
  669.   
  670. }  












2011-07-21 18:12:49 triple_zhao 阅读数 43

转载请注明来自: 5进制空间-android区

相信做电子书的同学,都遇到过翻页动画的需求吧,如果你不满足与点击滑动翻页的话,这边文章应该能够帮助到你。


先上个效果图:






效果还是很不错的,不过与ibook那个效果比起来,还是有差距的。应为这个没用到openGL做3D效果,只是用的2d的canvas画布去画的view,添加了阴影效果,还是挺有立体感的。而且比较流畅。openGL实现肯定效果会更好,不过就我目前的技术实力,实现希望还是渺茫的。

废话少说,还是上代码吧:

这里需要两个UI的view类和一个使用方法的demo。
第一个pageTurnerView.java

public class PageTurnerViewP1 extends RelativeLayout{
 
	  private static final int CORNER_RIGHT_MASK = 1;
	  private static final int CORNER_TOP_MASK = 2;
	  public static final int CORNER_BOTTOM_LEFT = 0;
	  public static final int CORNER_BOTTOM_RIGHT = 1;
	  public static final int CORNER_TOP_LEFT = 2;
	  public static final int CORNER_TOP_RIGHT = 3;
	  private static final int INVALIDATE = 1;
	  private static final int INITIAL_TIME_DELAY = 100;
	  private static final int TIME_DELAY = 10;
//	  private static final int TIME_STEPS = 30;
	  private boolean mPageTurning;
	  private boolean mStepping;
	  public long mNextTime;
	  private int mTimeStep;
	  private int mDrawnTimeStep;
	  private int mCorner;
	  private Drawable mBackPage;
	  private Drawable mPageBackground;
	  private Path mForegroundPath;
	  private Path mBackPagePath;
	  private Path mBackgroundPath;
	  private float mRotation;
	  private Rect mChildRect = new Rect();
	  private int mOuterOffsetX;
	  private int mOuterOffsetY;
	  public float mPivotX;
	  private int mPageId;
	  private PageViewP1 mPage;
	  private PointF mPageTurnCorner = new PointF();
	  private PointF mOppositeCorner = new PointF();
	  private PointF mPageDim = new PointF();
	  private int mStepLen = 1;
	  public static final int KEEP = 0;
	  public static final int NEXT = 1;
	  public static final int LAST = 2;
	  public int mWhere = KEEP;
	  public boolean isBgInit = true;
	  public boolean isBackInit = true;
	  private  float ax,ay,bx,by,cx,cy,dx,dy,ex,ey,c0x,c0y;
	  private int mMaxStep=30;
	  public final Handler mHandler = new Handler() {
		  public void handleMessage(Message msg) {
			  if (msg.what != 1) { return; }
//			  PageTurnerViewP1.this.invalidate();
			  refreshUI();
//			  PageTurnerViewP1.this.invalidate((int)bx, (int)ay, (int)dx, (int)dy);
			  if (PageTurnerViewP1.this.mStepping) { return; }
			  msg = obtainMessage(1);
			  long current = SystemClock.uptimeMillis();
			  if (PageTurnerViewP1.this.mNextTime &lt; current) { 				  //PageTurnerViewP1.access$102(PageTurnerViewP1.this, current + 10L); 				 PageTurnerViewP1.this.mNextTime= current + 5L; 			  } 			  sendMessageAtTime(msg, PageTurnerViewP1.this.mNextTime); 			  //PageTurnerViewP1.access$114(PageTurnerViewP1.this, 10L); 				PageTurnerViewP1.this.mNextTime+= 5L; 		  } 	  }; 	 	  public PageTurnerViewP1(Context context) { 		  super(context); 		  Log.i("==================== PageTurnerViewP1(Context context) =================", "" + this); 	  } 	  public PageTurnerViewP1(Context context, AttributeSet attrs) { 		  super(context, attrs); 			 		  this.mPageId = -1; 			this.mCorner = -1; 	  } 	  protected void onFinishInflate() { 		  super.onFinishInflate(); 		  if (this.mPageId != -1) { 			  this.mPage = ((PageViewP1)findViewById(this.mPageId)); 			  if (this.mPage != null) 				  this.mPage.setPageTurner(this); 		  } 	  } 	  public void setPageId(int pageId) { 		  this.mPageId = pageId; 		  this.mPage = ((PageViewP1)findViewById(this.mPageId)); 		  if (this.mPage != null) 			  this.mPage.setPageTurner(this); 	  } 	  public int getPageId() { 		  return this.mPageId; 	  } 	  public void setPage(PageViewP1 pageViewP1) { 		  this.mPage = pageViewP1; 	  } 	  public PageViewP1 getPage() { 		  return this.mPage; 	  } 	  public void setCorner(int corner) { 		  this.mCorner = corner; 	  } 	  public int getCorner() { 		  return this.mCorner; 	  } 	  protected void dispatchDraw(Canvas canvas) { 		   			Log.v("log dispatchDraw:", "drawing back page"+mPageTurning); //		  if ((this.mPageTurning) &amp;&amp; (this.mPage != null) &amp;&amp; (computePageTurn())) { 		  if ((computePageTurn())&amp;&amp; (this.mPageTurning) &amp;&amp; (this.mPage != null) ) { 			  this.mPage.setClipPath(this.mForegroundPath); 		  } 		  super.dispatchDraw(canvas); 		  if (this.mPageTurning) { 			  drawBackground(canvas); 			  drawBackPage(canvas); 			   			  if (!updateTimeStep()) { 				  this.mHandler.removeMessages(1); 				  if (this.mPage != null) { 					  this.mPage.onPageTurnFinished(canvas); 				  } 				  this.mPageTurning = false; 				  this.mStepping = false; 				  invalidate(); 			  } 		  } 	  } 	  public void startPageTurn(int mTimeStep) { 		  if ((this.mPage == null) &amp;&amp; (this.mPageId != -1)) { 			  this.mPage = ((PageViewP1)findViewById(this.mPageId)); 		  } 		  if (this.mPage == null) { 			  return; 		  } 		  this.mPage.setPageTurner(this); 		  Drawable d = this.mPage.getPageBackground(); 		  if (d != null) { 			  this.mPageBackground = d; 		  } 		  d = this.mPage.getBackPage(); 		  if (d != null) { 			  this.mBackPage = d; 		  } 		  int corner = this.mPage.getCorner(); 		  if (corner != -1) { 			  this.mCorner = corner; 		  } //		  this.mStepping=false; 		  this.mPageTurning = true; 		  this.mTimeStep = mTimeStep; 		  this.mDrawnTimeStep = -1; 		  Message msg = this.mHandler.obtainMessage(1); 		  this.mNextTime = (SystemClock.uptimeMillis() + 5L); 		  this.mHandler.sendMessageAtTime(msg, this.mNextTime); 	  } 	  public void stepPageTurn() { 		  if (!this.mStepping) { 			  this.mStepping = true; 			  startPageTurn(this.mTimeStep); 		  } else { //			 			  refreshUI(); 		  } 	  } 	  public void refreshUI(){ 		  computePageTurn(); //		  		  this.invalidate(); 	  } 	  private void sendUIhandler(){ 		  Message msg = this.mHandler.obtainMessage(1); 		  this.mNextTime = (SystemClock.uptimeMillis() + 30L); 		  this.mHandler.sendMessageAtTime(msg, this.mNextTime); 	  } 	  private boolean updateTimeStep() { 		  if (this.mTimeStep &gt;mMaxStep || this.mTimeStepthis.mMaxStep)) {
		  if ( (this.mTimeStep this.mMaxStep)) {
			  return false;
		  }
		  if (this.mPage == null) {
			  return false;
		  }
		  this.mDrawnTimeStep = this.mTimeStep;
		  View child = this.mPage.getChildAt(0);
		  child.getDrawingRect(this.mChildRect);
//		  this.mOuterOffsetX = (child.getLeft() - getLeft());
//		  this.mOuterOffsetY = (child.getTop() - getTop());
		  this.mOuterOffsetX = 0;
		  this.mOuterOffsetY = 0;
 
		  float width = this.mChildRect.right;
		  float height = this.mChildRect.bottom;
		  if(!mStepping){
			  this.mPivotX = (this.mTimeStep / 30.0f * width);
		  }
		  this.mForegroundPath = new Path();
		  this.mBackPagePath = new Path();
		  this.mBackgroundPath = new Path();
		  float slope = width / (this.mPivotX - width);
		  float y = this.mPivotX * slope;
 
		  this.mPageTurnCorner.x = 0.0F;
		  this.mPageTurnCorner.y = height;
		  this.mOppositeCorner.x = width;
		  this.mOppositeCorner.y = 0.0F;
		  float x0 = this.mPivotX;
		  float cornerIntersect = height * width / (height + width);
		  if ((this.mCorner &amp; 0x1) != 0) {
			  this.mPageTurnCorner.x = width;
			  this.mOppositeCorner.x = 0.0F;
			  x0 = width - x0;
		  }
 
		  if ((this.mCorner &amp; 0x2) != 0) {
			  this.mPageTurnCorner.y = 0.0F;
			  this.mOppositeCorner.y = height;
		  }
 
		  this.mPageDim.x = width;
		  this.mPageDim.y = height;
		  float page_slope;
 
		  if (this.mPivotX 2){
			LinearGradient grad = new LinearGradient(
					ex,ey,ex+(dx-ex)/4,ey+(dy-ey)/4,R.color.gray3,Color.TRANSPARENT,Shader.TileMode.CLAMP);
			Paint p=new Paint();
		    p.setShader(grad);
//		    p.setAlpha(120);
		    canvas.drawPath(this.mBackgroundPath,p);
		    //end test
		  	}
		  canvas.restore();
 
	  }
 
	  private void drawBackPage(Canvas canvas) {
		  float width = this.mChildRect.right;
		  float height = this.mChildRect.bottom;
		  canvas.save();
//		  canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
		  canvas.clipPath(this.mBackPagePath, Region.Op.INTERSECT);
		  float xShift = 2.0F * this.mPivotX - width;
		  float xRotate = width - this.mPivotX;
		  float yRotate = height;
		  if ((this.mCorner &amp; 0x1) != 0) {
			  xShift = width - 2.0F * this.mPivotX;
			  xRotate = this.mPivotX;
		  }
		  if ((this.mCorner &amp; 0x2) != 0) {
			  yRotate = 0.0F;
		  }
		  canvas.translate(this.mOuterOffsetX + xShift, this.mOuterOffsetY);
		  canvas.rotate(this.mRotation, xRotate, yRotate);
 
		  //画原本的背面
		  if (this.mBackPage != null) {
			  this.mBackPage.setBounds(0, 0, this.mChildRect.right, this.mChildRect.bottom);
			  this.mBackPage.draw(canvas);
		  }
		  //画回调函数中的画背面
		  if (this.mPage != null) {
				Log.v("log2 drawBackPage2:", "drawing back page");
			  this.mPage.drawBackPage(canvas);
		  }
 
		  canvas.restore();
		  canvas.save();
//
		    LinearGradient grad = new LinearGradient(
					ex,ey,ex-(ex-bx)/4,ey-(ey-by)/4,R.color.gray3,0xC9C9C9,Shader.TileMode.CLAMP);
			Paint p=new Paint();
		    p.setShader(grad);
//		    p.setAlpha(120);
		    canvas.drawPath(this.mBackPagePath,p);
		    canvas.restore();
		    //中间阴影问题,起点蓝色-》 白色-》 蓝色终点,这样起点前和终点后的区域也为蓝色了。
		    canvas.save();
//		    canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
		    LinearGradient grad1 = new LinearGradient(
		    		ex-(ex-bx)/4,ey-(ey-by)/4,bx,by,0xC9C9C9,R.color.gray3,Shader.TileMode.CLAMP);
			Paint p1=new Paint();
			p1.setShader(grad1);
//			p1.setAlpha(120);
		    canvas.drawPath(this.mBackPagePath,p1);
		    canvas.restore();
//		   
 
	  }
 
	  public int getmTimeStep(){
 
		  return mTimeStep;
	  }
	  public void setmTimeStep(int mTimeStep ){
 
		  this.mTimeStep= mTimeStep;
	  }
	  public boolean getmStepping(){
 
		  return mStepping;
	  }
	  public void setmStepping(boolean mStepping ){
 
		  this.mStepping= mStepping;
	  }
 
	  public void setmStepLen(int mStepLen){
		  this.mStepLen=mStepLen;
	  }
	  public int getmStepLen(){
		  return this.mStepLen;
	  }
 
	  public void setmMaxStep(int mMaxStep){
		  this.mMaxStep=mMaxStep;
	  }
	  public int getmMaxStep(){
		  return this.mMaxStep;
	  }
 
	public void setPreStart(int where)
	{
		switch (where)
		{
			case NEXT:
			case LAST:
				mWhere = where;
				break;
 
			default:
				mWhere = KEEP;
				break;
		}
 
		isBgInit = true;
		isBackInit = true;
 
	}
 
}
 

第二个view类pageView.java

public class PageViewP1 extends RelativeLayout {
	public static final int CORNER_BOTTOM_LEFT = 0;
	public static final int CORNER_BOTTOM_RIGHT = 1;
	public static final int CORNER_TOP_LEFT = 2;
	public static final int CORNER_TOP_RIGHT = 3;
	private Path mClipPath;
	private PageTurnerViewP1 mPageTurner;
	private Callback mCallback;
	private int mCorner;
	private Drawable mBackPage;
	private Drawable mPageBackground;
 
	public PageViewP1(Context context) {
		super(context);
	}
 
	public PageViewP1(Context context, AttributeSet attrs ) {
		super(context, attrs );
 
		this.mBackPage =this.getBackground();
		this.mCorner = -1;
	}
 
	void setPageTurner(PageTurnerViewP1 pageTurnerViewP1) {
		this.mPageTurner = pageTurnerViewP1;
	}
 
	void setClipPath(Path clipPath) {
		this.mClipPath = clipPath;
	}
 
	public void setCallback(Callback callback)  {
		this.mCallback = callback;
	}
 
	void drawBackPage(Canvas canvas) {
	   if (this.mCallback != null)
		   this.mCallback.onDrawBackPage(canvas);
	}
 
	void drawBackground(Canvas canvas) {
		if (this.mCallback != null)
			this.mCallback.onDrawBackground(canvas);
	}
 
	public void startPageTurn() {
		if (this.mPageTurner != null)
			this.mPageTurner.startPageTurn(0);
	}
 
	void onPageTurnFinished(Canvas canvas) {
		this.mCallback.onPageTurnFinished(canvas);
		this.mClipPath = null;
	}
 
	protected void dispatchDraw(Canvas canvas) {
		if (this.mClipPath != null) {
			canvas.save();
			canvas.clipPath(this.mClipPath, Region.Op.INTERSECT);
		}
		super.dispatchDraw(canvas);
		if (this.mClipPath != null)
			canvas.restore();
	}
 
	public void setCorner(int corner) {
		this.mCorner = corner;
	}
 
	public int getCorner() {
		return this.mCorner;
	}
 
	public void setBackPage(Drawable backPage) {
		this.mBackPage = backPage;
	}
 
	public Drawable getBackPage() {
		return this.mBackPage;
	}
 
	public void setPageBackground(Drawable background) {
		this.mPageBackground = background;
	}
 
	public Drawable getPageBackground() {
		return this.mPageBackground;
	}
 
	public static abstract class Callback {
		public void onDrawBackPage(Canvas canvas) {
			Log.v("Callback", "drawing back page");
		}
		public void onDrawBackground(Canvas canvas) {
			Log.v("Callback2", "drawing back page");
		}
		public void onPageTurnFinished(Canvas canvas) {
			Log.v("Callback3", "drawing back page");
		}
	}
}
      转载请注明来自: 5进制空间-android区

如果这两个view类没研究明白怎么用的话,可以去android 翻页卷曲效果里面寻找获取pageDemo.java,获得使用方法。

2012-10-08 11:44:25 xiang279416228 阅读数 692

现在智能手机上看电子书越来越流行,前段时间也像做个类似的应用,但是翻页效果不知道如何做,于是网上收罗了一番,发现了一个比较好的电子书翻页效果,发出来与大家一起分享。

截图如下:


源码下载地址:http://www.iwapzone.com/html/app/xinwenyuedu/2012/0919/472.html

2011-11-07 22:13:54 TT5267621 阅读数 2393

 android 翻页卷曲 电子书DEMO

 

 

 

我的真机测试结果:
测试卷曲DEMO环境三星T959 手机一部 系统 android 2.3
测试txt文件位置:请自行将z8806c.txt放置SDcard 根目录,进行测试
测试txt文件大小:98.5 MB(103,387,040 字节)电子书文件一个(为了复制出这么大的文本文件,电脑足足卡了20多分钟,实际中应该没有这么大的电子书,我想说明什么,你懂的.....不解释)
读取此文本时间:低于0.5毫秒(貌似夸张了一点)

 

DEMO下载地址:http://download.csdn.net/detail/tt5267621/3767401

2019-05-19 12:40:21 qq_39925376 阅读数 225

//读取文件,设置翻页时的阴影和背面文字

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 = 10; // 左右与边缘的距离
	private int marginHeight = 15; // 上下与边缘的距离
	private int mLineCount; // 每页可以显示的行数
	private float mVisibleHeight; // 绘制内容的宽
	private float mVisibleWidth; // 绘制内容的宽
	private boolean m_isfirstPage,m_islastPage;
	private Paint mPaint;
	public BookPageFactory(int w, int h) {
		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;
		m_mbBuf = new RandomAccessFile(book_file, "r").getChannel().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--;
			}
		}
		if (i < 0)
			i = 0;
		int nParaSize = nEnd - i;
		int j;
		byte[] buf = new byte[nParaSize];
		for (j = 0; j < nParaSize; j++) {
			buf[j] = m_mbBuf.get(i + j);
		}
		return buf;
	}
	// 读取上一段落
	protected byte[] readParagraphForward(int nFromPos) {
		int nStart = nFromPos;
		int i = nStart;
		byte b0, b1;
		// 根据编码格式判断换行
		if (m_strCharsetName.equals("UTF-16LE")) {
			while (i < m_mbBufLen - 1) {
				b0 = m_mbBuf.get(i++);
				b1 = m_mbBuf.get(i++);
				if (b0 == 0x0a && b1 == 0x00) {
					break;
				}
			}
		} else if (m_strCharsetName.equals("UTF-16BE")) {
			while (i < m_mbBufLen - 1) {
				b0 = m_mbBuf.get(i++);
				b1 = m_mbBuf.get(i++);
				if (b0 == 0x00 && b1 == 0x0a) {
					break;
				}
			}
		} else {
			while (i < m_mbBufLen) {
				b0 = m_mbBuf.get(i++);
				if (b0 == 0x0a) {
					break;
				}
			}
		}
		int nParaSize = i - nStart;
		byte[] buf = new byte[nParaSize];
		for (i = 0; i < nParaSize; i++) {
			buf[i] = m_mbBuf.get(nFromPos + i);
		}
		return buf;
	}
	
	protected Vector<String> pageDown() {
		String strParagraph = "";
		Vector<String> lines = new Vector<String>();
		while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen) {
			byte[] paraBuf = readParagraphForward(m_mbBufEnd); 
			// 读取一个段落
			m_mbBufEnd += paraBuf.length;
			try {
				strParagraph = new String(paraBuf, m_strCharsetName);
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String strReturn = "";
			if (strParagraph.indexOf("\r\n") != -1) {
				strReturn = "\r\n";
				strParagraph = strParagraph.replaceAll("\r\n", "");
			} else if (strParagraph.indexOf("\n") != -1) {
				strReturn = "\n";
				strParagraph = strParagraph.replaceAll("\n", "");
			}

			if (strParagraph.length() == 0) {
				lines.add(strParagraph);
			}
			while (strParagraph.length() > 0) {
				int nSize = mPaint.breakText(strParagraph, true,
				 mVisibleWidth,
						null);
				lines.add(strParagraph.substring(0, nSize));
				strParagraph = strParagraph.substring(nSize);
				if (lines.size() >= mLineCount) {
					break;
				}
			}
			if (strParagraph.length() != 0) {
				try {
					m_mbBufEnd -= (strParagraph + strReturn)
							.getBytes(m_strCharsetName).length;
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return lines;
	}
	
	protected void pageUp() {
		if (m_mbBufBegin < 0)
			m_mbBufBegin = 0;
		Vector<String> lines = new Vector<String>();
		String strParagraph = "";
		while (lines.size() < mLineCount && m_mbBufBegin > 0) {
			Vector<String> paraLines = new Vector<String>();
			byte[] paraBuf = readParagraphBack(m_mbBufBegin);
			m_mbBufBegin -= paraBuf.length;
			try {
				strParagraph = new String(paraBuf, m_strCharsetName);
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			strParagraph = strParagraph.replaceAll("\r\n", "");
			strParagraph = strParagraph.replaceAll("\n", "");

			if (strParagraph.length() == 0) {
				paraLines.add(strParagraph);
			}
			while (strParagraph.length() > 0) {
				int nSize = mPaint.breakText(strParagraph, true,
				 mVisibleWidth,
						null);
				paraLines.add(strParagraph.substring(0, nSize));
				strParagraph = strParagraph.substring(nSize);
			}
			lines.addAll(0, paraLines);
		}
		while (lines.size() > mLineCount) {
			try {
				m_mbBufBegin += lines.get(0).
				getBytes(m_strCharsetName).length;
				lines.remove(0);
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		m_mbBufEnd = m_mbBufBegin;
		return;
	}
	
	protected void prePage() throws IOException {
		if (m_mbBufBegin <= 0) {
			m_mbBufBegin = 0;
			m_isfirstPage=true;
			return;
		}else m_isfirstPage=false;
		m_lines.clear();
		pageUp();
		m_lines = pageDown();
	}

	public void nextPage() throws IOException {
		if (m_mbBufEnd >= m_mbBufLen) {
			m_islastPage=true;
			return;
		}else m_islastPage=false;
		m_lines.clear();
		m_mbBufBegin = m_mbBufEnd;
		m_lines = pageDown();
	}

	public void onDraw(Canvas c) {
		if (m_lines.size() == 0)
			m_lines = pageDown();
		if (m_lines.size() > 0) {
			if (m_book_bg == null)
				c.drawColor(m_backColor);
			else
				c.drawBitmap(m_book_bg, 0, 0, null);
			int y = marginHeight;
			for (String strLine : m_lines) {
				y += m_fontSize;
				c.drawText(strLine, marginWidth, y, mPaint);
			}
		}
		float fPercent = (float) (m_mbBufBegin * 1.0 / m_mbBufLen);
		DecimalFormat df = new DecimalFormat("#0.0");
		String strPercent = df.format(fPercent * 100) + "%";
		int nPercentWidth = (int) mPaint.measureText("999.9%") + 1;
		c.drawText(strPercent, mWidth - nPercentWidth, mHeight - 5, mPaint);
	}

	public void setBgBitmap(Bitmap BG) {
		m_book_bg = BG;
	}
	
	public boolean isfirstPage() {
		return m_isfirstPage;
	}
	
	public boolean islastPage() {
		return m_islastPage;
	}
}

//电子书阅读主类

public class Turntest extends Activity {
	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);

		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() {
			public boolean onTouch(View v, MotionEvent e) {
				boolean ret=false;
				if (v == mPageWidget) {
					if (e.getAction() == MotionEvent.ACTION_DOWN) {
						mPageWidget.abortAnimation();
						mPageWidget.calcCornerXY(e.getX(), e.getY());

						pagefactory.onDraw(mCurPageCanvas);
						if (mPageWidget.DragToRight()) {
							try {
								pagefactory.prePage();
							} catch (IOException e1) {
								// TODO Auto-generated catch block
								e1.printStackTrace();
							}						
							if(pagefactory.isfirstPage())return false;
							pagefactory.onDraw(mNextPageCanvas);
						} else {
							try {
								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;
			}
		});
	}
}

在这里插入图片描述

没有更多推荐了,返回首页