android 电子书源码,翻页效果

来源:互联网 发布:男装推荐 知乎 编辑:程序博客网 时间:2024/05/17 13:40

这两天模仿着做了一个apk电子书的应用,有翻页效果,本来是想学一下自己写的,无奈,最后偷懒使用了别人写的 翻页类 PageWidget.java


下面是工程文件的结构


这个是写的类的包结构,PageView.java 类本类是打算自己写的,然后学习安卓动画效果,但是由于时间加上懒,再加上看晕了,就使用了别人写的PageWidger.java类。来源我忘了,当时搜索到的,本来是打算学习的。

好了下面,插入代码:

HomeActivity.java

package com.horse;import com.horse.R;import com.horse.bean.Book;import com.horse.dialog.AboutDialog;import android.app.Activity;import android.app.Dialog;import android.content.Intent;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.AdapterView;import android.widget.ListView;import android.widget.TextView;import android.widget.AdapterView.OnItemClickListener;public class HomeActivity extends Activity {private ListView booklistLv;private TextView booknameTv;private Book book;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.home_activity);booklistLv = (ListView) findViewById(R.id.booklist_lv);booknameTv = (TextView) findViewById(R.id.bookname_tv);book = Book.getInstance();booklistLv.setOnItemClickListener(itemListener);init();}private void init() {booknameTv.setText(book.getBookname());fillBooklistLv();}private void fillBooklistLv(){BooklistAdapter bAdapter = new BooklistAdapter(book.getChapterList(),this);booklistLv.setAdapter(bAdapter);}private OnItemClickListener itemListener = new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {Intent intent = new Intent(HomeActivity.this,ViewBookActivity.class);intent.putExtra("listorder", position);startActivity(intent);}};public boolean onCreateOptionsMenu(Menu menu) {      menu.add(0, 1, 0, "关于");      return super.onCreateOptionsMenu(menu);  }  public boolean onOptionsItemSelected(MenuItem item) {AboutDialog dia = new AboutDialog(HomeActivity.this);dia.show();dia.setAboutTv(getString(R.string.developer));return true;}}
ViewBookActivity.java

package com.horse;import com.horse.R;import com.horse.bean.Chapter;import com.horse.util.BookPage;import com.horse.util.IOHelper;import com.horse.view.PageWidget;import android.app.Activity;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.os.Bundle;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.view.View.OnTouchListener;public class ViewBookActivity extends Activity{/*private TextView booktitleTv;private TextView bookcontentTv;*/private PageWidget pageWidget;private Bitmap curBitmap, nextBitmap;private Canvas curCanvas, nextCanvas;private BookPage bookpage ;private Chapter chapter;protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);initChapter();DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);int w = dm.widthPixels;int h = dm.heightPixels;System.out.println(w + "\t" + h);curBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);nextBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);curCanvas = new Canvas(curBitmap);nextCanvas = new Canvas(nextBitmap);bookpage = new BookPage(w, h, chapter);bookpage.setBgBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.bg));bookpage.draw(curCanvas);pageWidget = new PageWidget(this, w, h);setContentView(pageWidget);pageWidget.setBitmaps(curBitmap, curBitmap);pageWidget.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent e) {// TODO Auto-generated method stubboolean ret = false;boolean toAnotherChapter = true;if (v == pageWidget) {if (e.getAction() == MotionEvent.ACTION_DOWN) {pageWidget.abortAnimation();pageWidget.calcCornerXY(e.getX(), e.getY());bookpage.draw(curCanvas);if (pageWidget.DragToRight()) {if(bookpage.prePage()){bookpage.draw(nextCanvas);} elsereturn false;} else {if (bookpage.nextPage()){bookpage.draw(nextCanvas);}elsereturn false;}pageWidget.setBitmaps(curBitmap, nextBitmap);}ret = pageWidget.doTouchEvent(e);return ret;}return false;}});}private void init(){initChapter();/*booktitleTv.setText(chapter.getTitle());bookcontentTv.setText(chapter.getContent());*/}private void initChapter(){Intent intent = getIntent();int order = intent.getIntExtra("listorder", -1);chapter = IOHelper.getChapter(order);}}

BookPage.java

package com.horse.util;import java.text.DecimalFormat;import java.util.Vector;import com.horse.bean.Chapter;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Align;import android.text.format.Time;/** * 这个类的目的是为在看书翻页时,需要进行的动作提供接口。 * 包括翻向下一页,翻向上一页。在翻到每章最后一页时,如果后面还有章节就继续翻向下一章节,没有就向用户显示已读完。 * 在翻向上一章节时,如果前面还有章节,就翻到上一章节,没有就向用户显示,这已经是第一章节。 *  * 在直觉上认为这个应该只设置成一个接口,因为只需向视图层提供动作接口,也就是本类应属于模型层。则其设置为一个借口可能也合适。 * 但是如果设置成一个接口,那么接口的实现类,有多个都要保存的数据。那么为了代码重用,抽象类可能比接口更加合适。 上面是个人分析,可能不是很合适。 *  * @author MJZ *  */public class BookPage {// configuration informationprivate int screenWidth; // 屏幕宽度private int screenHeight; // 屏幕高度private int fontSize; // 字体大小private int lineHgight;//每行的高度private int marginWidth = 15; // 左右与边缘的距离private int marginHeight = 15; // 上下与边缘的距离private int textColor; // 字体颜色private Bitmap bgBitmap; // 背景图片private int bgColor; // 背景颜色private Paint paint;private Paint paintBottom;private int visibleWidth; // 屏幕中可显示文本的宽度private int visibleHeight;private Chapter chapter; // 需要处理的章节对象private Vector<String> linesVe; // 将章节內容分成行,并将每页按行存储到vector对象中private int lineCount; // 一个章节在当前配置下一共有多少行private String content;private int chapterLen; // 章节的长度// private int curCharPos; // 当前字符在章节中所在位置private int charBegin; // 每一页第一个字符在章节中的位置private int charEnd; // 每一页最后一个字符在章节中的位置private boolean isfirstPage;private boolean islastPage;private Vector<Vector<String>> pagesVe;int pageNum;/** * 在新建一个BookPage对象时,需要向其提供数据,以支持屏幕翻页功能。 *  * @param screenWidth *            屏幕宽度,用来计算每行显示多少字 * @param screenHeight *            屏幕高度,用来计算每页显示多少行 * @param chapter *            章节对象 */public BookPage(int screenWidth, int screenHeight, Chapter chapter) {this.screenHeight = screenHeight;this.screenWidth = screenWidth;this.chapter = chapter;init();}/** * 初始最好按照定义变量的顺序来初始化,统一。在将来需要修改某个变量的时候,容易找到。 对代码维护应该也很有用吧。 */protected void init() {bgBitmap = null;bgColor = 0xffff9e85;textColor = Color.BLACK;content = chapter.getContent();chapterLen = content.length();// curCharPos = 0;charBegin = 0;charEnd = 0;fontSize = 30;lineHgight = fontSize + 8;linesVe = new Vector<String>();paint = new Paint(Paint.ANTI_ALIAS_FLAG);paint.setTextAlign(Align.LEFT);paint.setTextSize(fontSize);paint.setColor(textColor);paintBottom = new Paint(Paint.ANTI_ALIAS_FLAG);paintBottom.setTextAlign(Align.LEFT);paintBottom.setTextSize(fontSize / 2);paintBottom.setColor(textColor);visibleWidth = screenWidth - marginWidth * 2;visibleHeight = screenHeight - marginHeight * 2;lineCount = visibleHeight / lineHgight - 2;isfirstPage = true;islastPage = false;pagesVe = new Vector<Vector<String>>();pageNum = -1;slicePage();}public Vector<String> getCurPage() {return linesVe;}protected void slicePage() {pagesVe.clear();int curPos = 0;while (curPos < chapterLen) {Vector<String> lines = new Vector<String>();charBegin = curPos;while (lines.size() < lineCount && curPos < chapterLen) {int i = content.indexOf("\n", curPos);String paragraphStr = content.substring(curPos, i);// curCharPos += i;if (curPos == i)lines.add("");while (paragraphStr.length() > 0) {int horSize = paint.breakText(paragraphStr, true,visibleWidth, null);lines.add(paragraphStr.substring(0, horSize));paragraphStr = paragraphStr.substring(horSize);curPos += horSize;if (lines.size() > lineCount)break;}// 如果是把一整段读取完的话,需要给当前位置加1if (paragraphStr.length() == 0)curPos += "\n".length();}pagesVe.add(lines);}}/** * 翻到下一页 */public boolean nextPage() {if (isLastPage()) {if (!nextChapter()) // 如果已经到本书末尾,那么不能继续执行翻页代码return false;}/* * Vector<String> lines = new Vector<String>(); charBegin = charEnd; * while (lines.size() < lineCount && charEnd < chapterLen) { int i = * content.indexOf("\n", charEnd); String paragraphStr = * content.substring(charEnd, i); // curCharPos += i; if (charEnd == i) * lines.add(""); *  * while (paragraphStr.length() > 0) { int horSize = * paint.breakText(paragraphStr, true, visibleWidth, null); * lines.add(paragraphStr.substring(0, horSize)); paragraphStr = * paragraphStr.substring(horSize); charEnd += horSize; if (lines.size() * > lineCount) break; } // 如果是把一整段读取完的话,需要给当前位置加1 if * (paragraphStr.length() == 0) charEnd += "\n".length(); } linesVe = * lines; */linesVe = pagesVe.get(++pageNum);return true;}/** * 翻到上一页 */public boolean prePage() {if (isFirstPage()) {if (!preChapter()) // 如果已经到本书第一章,就不能继续执行翻页代码return false;}/* * Vector<String> lines = new Vector<String>(); String backStr = * content.substring(0, charBegin); charEnd = charBegin; *  * while (lines.size() < lineCount && charBegin > 0) { int i = * backStr.lastIndexOf("\n"); if(i == -1) i = 0; String paragraphStr = * backStr.substring(i, charBegin); Vector<String> vet = new * Vector<String>(lines); *  * // if(charBegin == i)lines.add(""); *  * while (paragraphStr.length() > 0) { int horSize = * paint.breakText(paragraphStr, true, visibleWidth, null); * lines.add(paragraphStr.substring(0, horSize)); paragraphStr = * paragraphStr.substring(horSize); charBegin -= horSize; if * (lines.size() > lineCount) break; } *  * backStr = content.substring(0, charBegin); int j = -1; for (String * line : vet) lines.insertElementAt(line, ++j); } linesVe = lines; */linesVe = pagesVe.get(--pageNum);return true;}/** * 跳到下一章,若返回值为false,则当前章节已经为最后一章 */public boolean nextChapter() {int order = chapter.getOrder();Chapter tempChapter = IOHelper.getChapter(order + 1);if (tempChapter == null)return false;chapter = tempChapter;content = chapter.getContent();chapterLen = content.length();// curCharPos = 0;charBegin = 0;charEnd = 0;slicePage();pageNum = -1;return true;}/** * 跳到上一章,若返回值为false,则当前章节已经为第一章 */public boolean preChapter() {int order = chapter.getOrder();Chapter tempChapter = IOHelper.getChapter(order - 1);if (tempChapter == null)return false;chapter = tempChapter;content = chapter.getContent();chapterLen = content.length();// curCharPos = chapterLen;charBegin = chapterLen;charEnd = chapterLen;slicePage();pageNum = pagesVe.size();return true;}public boolean isFirstPage() {if (pageNum <= 0)return true;return false;}public boolean isLastPage() {if (pageNum >= pagesVe.size() - 1)return true;return false;}public void draw(Canvas c) {if (linesVe.size() == 0)nextPage();if (linesVe.size() > 0) {if (bgBitmap == null)c.drawColor(bgColor);elsec.drawBitmap(bgBitmap, 0, 0, null);int y = marginHeight;for (String line : linesVe) {y += lineHgight;c.drawText(line, marginWidth, y, paint);}}// float percent = (float) (charBegin * 1.0 / chapterLen);float percent = (float) ((pageNum + 1) * 1.0 / pagesVe.size());DecimalFormat df = new DecimalFormat("#0.0");String percetStr = df.format(percent * 100) + "%";Time time = new Time();time.setToNow();String timeStr;if (time.minute < 10)timeStr = "" + time.hour + " : 0" + time.minute;elsetimeStr = "" + time.hour + " : " + time.minute;int pSWidth = (int) paintBottom.measureText("99.9%") + 2;int titWidth = (int) paintBottom.measureText(chapter.getTitle());c.drawText(timeStr, marginWidth / 2, screenHeight - 5, paintBottom);c.drawText(chapter.getTitle(), screenWidth / 2 - titWidth / 2,screenHeight - 5, paintBottom);c.drawText(percetStr, screenWidth - pSWidth, screenHeight - 5, paintBottom);}public void setBgBitmap(Bitmap bMap) {bgBitmap = Bitmap.createScaledBitmap(bMap, screenWidth, screenHeight,true);}}

PageWidget.java
package com.horse.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.ColorMatrix;import android.graphics.ColorMatrixColorFilter;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PointF;import android.graphics.Region;import android.graphics.drawable.GradientDrawable;import android.view.MotionEvent;import android.view.View;import android.widget.Scroller;public class PageWidget extends View {private int mWidth;private int mHeight;private int mCornerX = 0; // 拖拽点对应的页脚private int mCornerY = 0;private Path mPath0;private Path mPath1;Bitmap mCurPageBitmap = null; // 当前页Bitmap mNextPageBitmap = null;PointF mTouch = new PointF(); // 拖拽点PointF mBezierStart1 = new PointF(); // 贝塞尔曲线起始点PointF mBezierControl1 = new PointF(); // 贝塞尔曲线控制点PointF mBeziervertex1 = new PointF(); // 贝塞尔曲线顶点PointF mBezierEnd1 = new PointF(); // 贝塞尔曲线结束点PointF mBezierStart2 = new PointF(); // 另一条贝塞尔曲线PointF mBezierControl2 = new PointF();PointF mBeziervertex2 = new PointF();PointF mBezierEnd2 = new PointF();float mMiddleX;float mMiddleY;float mDegrees;float mTouchToCornerDis;ColorMatrixColorFilter mColorMatrixFilter;Matrix mMatrix;float[] mMatrixArray = { 0, 0, 0, 0, 0, 0, 0, 0, 1.0f };boolean mIsRTandLB; // 是否属于右上左下float mMaxLength = (float) Math.hypot(mWidth, mHeight);int[] mBackShadowColors;int[] mFrontShadowColors;GradientDrawable mBackShadowDrawableLR;GradientDrawable mBackShadowDrawableRL;GradientDrawable mFolderShadowDrawableLR;GradientDrawable mFolderShadowDrawableRL;GradientDrawable mFrontShadowDrawableHBT;GradientDrawable mFrontShadowDrawableHTB;GradientDrawable mFrontShadowDrawableVLR;GradientDrawable mFrontShadowDrawableVRL;Paint mPaint;Scroller mScroller;public PageWidget(Context context, int w, int h) {super(context);// TODO Auto-generated constructor stubmWidth = w;mHeight = h;mPath0 = new Path();mPath1 = new Path();createDrawable();mPaint = new Paint();mPaint.setStyle(Paint.Style.FILL);ColorMatrix cm = new ColorMatrix();float array[] = { 0.55f, 0, 0, 0, 80.0f, 0, 0.55f, 0, 0, 80.0f, 0, 0,0.55f, 0, 80.0f, 0, 0, 0, 0.2f, 0 };cm.set(array);mColorMatrixFilter = new ColorMatrixColorFilter(cm);mMatrix = new Matrix();mScroller = new Scroller(getContext());mTouch.x = 0.01f; // 不让x,y为0,否则在点计算时会有问题mTouch.y = 0.01f;}/** * Author : hmg25 Version: 1.0 Description : 计算拖拽点对应的拖拽脚 */public void calcCornerXY(float x, float y) {if (x <= mWidth / 2)mCornerX = 0;elsemCornerX = mWidth;if (y <= mHeight / 2)mCornerY = 0;elsemCornerY = mHeight;// 有什么意思if ((mCornerX == 0 && mCornerY == mHeight)|| (mCornerX == mWidth && mCornerY == 0))mIsRTandLB = true;elsemIsRTandLB = false;}public boolean doTouchEvent(MotionEvent event) {// TODO Auto-generated method stubif (event.getAction() == MotionEvent.ACTION_MOVE) {mTouch.x = event.getX();mTouch.y = event.getY();this.postInvalidate();}if (event.getAction() == MotionEvent.ACTION_DOWN) {mTouch.x = event.getX();mTouch.y = event.getY();// calcCornerXY(mTouch.x, mTouch.y);// this.postInvalidate();}if (event.getAction() == MotionEvent.ACTION_UP) {if (canDragOver()) {startAnimation(1200);} else {mTouch.x = mCornerX - 0.09f;mTouch.y = mCornerY - 0.09f;}this.postInvalidate();}// return super.onTouchEvent(event);return true;}/** * Author : hmg25 Version: 1.0 Description : 求解直线P1P2和直线P3P4的交点坐标 */public PointF getCross(PointF P1, PointF P2, PointF P3, PointF P4) {PointF CrossP = new PointF();// 二元函数通式: y=ax+bfloat 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;}private void calcPoints() {mMiddleX = (mTouch.x + mCornerX) / 2;mMiddleY = (mTouch.y + mCornerY) / 2;mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)* (mCornerY - mMiddleY) / (mCornerX - mMiddleX);mBezierControl1.y = mCornerY;mBezierControl2.x = mCornerX;mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)* (mCornerX - mMiddleX) / (mCornerY - mMiddleY);// Log.i("hmg", "mTouchX  " + mTouch.x + "  mTouchY  " + mTouch.y);// Log.i("hmg", "mBezierControl1.x  " + mBezierControl1.x// + "  mBezierControl1.y  " + mBezierControl1.y);// Log.i("hmg", "mBezierControl2.x  " + mBezierControl2.x// + "  mBezierControl2.y  " + mBezierControl2.y);mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x)/ 2;mBezierStart1.y = mCornerY;// 当mBezierStart1.x < 0或者mBezierStart1.x > 480时// 如果继续翻页,会出现BUG故在此限制if (mTouch.x > 0 && mTouch.x < mWidth) {if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth) {if (mBezierStart1.x < 0)mBezierStart1.x = mWidth - mBezierStart1.x;float f1 = Math.abs(mCornerX - mTouch.x);float f2 = mWidth * f1 / mBezierStart1.x;mTouch.x = Math.abs(mCornerX - f2);float f3 = Math.abs(mCornerX - mTouch.x)* Math.abs(mCornerY - mTouch.y) / f1;mTouch.y = Math.abs(mCornerY - f3);mMiddleX = (mTouch.x + mCornerX) / 2;mMiddleY = (mTouch.y + mCornerY) / 2;mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY)* (mCornerY - mMiddleY) / (mCornerX - mMiddleX);mBezierControl1.y = mCornerY;mBezierControl2.x = mCornerX;mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX)* (mCornerX - mMiddleX) / (mCornerY - mMiddleY);// Log.i("hmg", "mTouchX --> " + mTouch.x + "  mTouchY-->  "// + mTouch.y);// Log.i("hmg", "mBezierControl1.x--  " + mBezierControl1.x// + "  mBezierControl1.y -- " + mBezierControl1.y);// Log.i("hmg", "mBezierControl2.x -- " + mBezierControl2.x// + "  mBezierControl2.y -- " + mBezierControl2.y);mBezierStart1.x = mBezierControl1.x- (mCornerX - mBezierControl1.x) / 2;}}mBezierStart2.x = mCornerX;mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y)/ 2;mTouchToCornerDis = (float) Math.hypot((mTouch.x - mCornerX),(mTouch.y - mCornerY));mBezierEnd1 = getCross(mTouch, mBezierControl1, mBezierStart1,mBezierStart2);mBezierEnd2 = getCross(mTouch, mBezierControl2, mBezierStart1,mBezierStart2);// Log.i("hmg", "mBezierEnd1.x  " + mBezierEnd1.x + "  mBezierEnd1.y  "// + mBezierEnd1.y);// Log.i("hmg", "mBezierEnd2.x  " + mBezierEnd2.x + "  mBezierEnd2.y  "// + mBezierEnd2.y);/* * mBeziervertex1.x 推导 * ((mBezierStart1.x+mBezierEnd1.x)/2+mBezierControl1.x)/2 化简等价于 * (mBezierStart1.x+ 2*mBezierControl1.x+mBezierEnd1.x) / 4 */mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4;mBeziervertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4;mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4;mBeziervertex2.y = (2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4;}private void drawCurrentPageArea(Canvas canvas, Bitmap bitmap, Path path) {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.save();canvas.clipPath(path, Region.Op.XOR);canvas.drawBitmap(bitmap, 0, 0, null);canvas.restore();}private void drawNextPageAreaAndShadow(Canvas canvas, Bitmap bitmap) {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();mDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl1.x- mCornerX, mBezierControl2.y - mCornerY));int leftx;int rightx;GradientDrawable mBackShadowDrawable;if (mIsRTandLB) {leftx = (int) (mBezierStart1.x);rightx = (int) (mBezierStart1.x + mTouchToCornerDis / 4);mBackShadowDrawable = mBackShadowDrawableLR;} else {leftx = (int) (mBezierStart1.x - mTouchToCornerDis / 4);rightx = (int) mBezierStart1.x;mBackShadowDrawable = mBackShadowDrawableRL;}canvas.save();canvas.clipPath(mPath0);canvas.clipPath(mPath1, Region.Op.INTERSECT);canvas.drawBitmap(bitmap, 0, 0, null);canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y);mBackShadowDrawable.setBounds(leftx, (int) mBezierStart1.y, rightx,(int) (mMaxLength + mBezierStart1.y));mBackShadowDrawable.draw(canvas);canvas.restore();}public void setBitmaps(Bitmap bm1, Bitmap bm2) {mCurPageBitmap = bm1;mNextPageBitmap = bm2;}public void setScreen(int w, int h) {mWidth = w;mHeight = h;}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawColor(0xFFAAAAAA);calcPoints();drawCurrentPageArea(canvas, mCurPageBitmap, mPath0);drawNextPageAreaAndShadow(canvas, mNextPageBitmap);drawCurrentPageShadow(canvas);drawCurrentBackArea(canvas, mCurPageBitmap);}/** * Author : hmg25 Version: 1.0 Description : 创建阴影的GradientDrawable */private void createDrawable() {int[] color = { 0x333333, 0xb0333333 };mFolderShadowDrawableRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, color);mFolderShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);mFolderShadowDrawableLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, color);mFolderShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);mBackShadowColors = new int[] { 0xff111111, 0x111111 };mBackShadowDrawableRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors);mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);mBackShadowDrawableLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors);mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);mFrontShadowColors = new int[] { 0x80111111, 0x111111 };mFrontShadowDrawableVLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors);mFrontShadowDrawableVLR.setGradientType(GradientDrawable.LINEAR_GRADIENT);mFrontShadowDrawableVRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors);mFrontShadowDrawableVRL.setGradientType(GradientDrawable.LINEAR_GRADIENT);mFrontShadowDrawableHTB = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors);mFrontShadowDrawableHTB.setGradientType(GradientDrawable.LINEAR_GRADIENT);mFrontShadowDrawableHBT = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors);mFrontShadowDrawableHBT.setGradientType(GradientDrawable.LINEAR_GRADIENT);}/** * Author : hmg25 Version: 1.0 Description : 绘制翻起页的阴影 */public void drawCurrentPageShadow(Canvas canvas) {double degree;if (mIsRTandLB) {degree = Math.PI/ 4- Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x- mBezierControl1.x);} else {degree = Math.PI/ 4- Math.atan2(mTouch.y - mBezierControl1.y, mTouch.x- mBezierControl1.x);}// 翻起页阴影顶点与touch点的距离double d1 = (float) 25 * 1.414 * Math.cos(degree);double d2 = (float) 25 * 1.414 * Math.sin(degree);float x = (float) (mTouch.x + d1);float y;if (mIsRTandLB) {y = (float) (mTouch.y + d2);} else {y = (float) (mTouch.y - d2);}mPath1.reset();mPath1.moveTo(x, y);mPath1.lineTo(mTouch.x, mTouch.y);mPath1.lineTo(mBezierControl1.x, mBezierControl1.y);mPath1.lineTo(mBezierStart1.x, mBezierStart1.y);mPath1.close();float rotateDegrees;canvas.save();canvas.clipPath(mPath0, Region.Op.XOR);canvas.clipPath(mPath1, Region.Op.INTERSECT);int leftx;int rightx;GradientDrawable mCurrentPageShadow;if (mIsRTandLB) {leftx = (int) (mBezierControl1.x);rightx = (int) mBezierControl1.x + 25;mCurrentPageShadow = mFrontShadowDrawableVLR;} else {leftx = (int) (mBezierControl1.x - 25);rightx = (int) mBezierControl1.x + 1;mCurrentPageShadow = mFrontShadowDrawableVRL;}rotateDegrees = (float) Math.toDegrees(Math.atan2(mTouch.x- mBezierControl1.x, mBezierControl1.y - mTouch.y));canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y);mCurrentPageShadow.setBounds(leftx,(int) (mBezierControl1.y - mMaxLength), rightx,(int) (mBezierControl1.y));mCurrentPageShadow.draw(canvas);canvas.restore();mPath1.reset();mPath1.moveTo(x, y);mPath1.lineTo(mTouch.x, mTouch.y);mPath1.lineTo(mBezierControl2.x, mBezierControl2.y);mPath1.lineTo(mBezierStart2.x, mBezierStart2.y);mPath1.close();canvas.save();canvas.clipPath(mPath0, Region.Op.XOR);canvas.clipPath(mPath1, Region.Op.INTERSECT);if (mIsRTandLB) {leftx = (int) (mBezierControl2.y);rightx = (int) (mBezierControl2.y + 25);mCurrentPageShadow = mFrontShadowDrawableHTB;} else {leftx = (int) (mBezierControl2.y - 25);rightx = (int) (mBezierControl2.y + 1);mCurrentPageShadow = mFrontShadowDrawableHBT;}rotateDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl2.y- mTouch.y, mBezierControl2.x - mTouch.x));canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y);float temp;if (mBezierControl2.y < 0)temp = mBezierControl2.y - mHeight;elsetemp = mBezierControl2.y;int hmg = (int) Math.hypot(mBezierControl2.x, temp);if (hmg > mMaxLength)mCurrentPageShadow.setBounds((int) (mBezierControl2.x - 25) - hmg, leftx,(int) (mBezierControl2.x + mMaxLength) - hmg,rightx);elsemCurrentPageShadow.setBounds((int) (mBezierControl2.x - mMaxLength), leftx,(int) (mBezierControl2.x), rightx);// Log.i("hmg", "mBezierControl2.x   " + mBezierControl2.x// + "  mBezierControl2.y  " + mBezierControl2.y);mCurrentPageShadow.draw(canvas);canvas.restore();}/** * Author : hmg25 Version: 1.0 Description : 绘制翻起页背面 */private void drawCurrentBackArea(Canvas canvas, Bitmap bitmap) {int i = (int) (mBezierStart1.x + mBezierControl1.x) / 2;float f1 = Math.abs(i - mBezierControl1.x);int i1 = (int) (mBezierStart2.y + mBezierControl2.y) / 2;float f2 = Math.abs(i1 - mBezierControl2.y);float f3 = Math.min(f1, f2);mPath1.reset();mPath1.moveTo(mBeziervertex2.x, mBeziervertex2.y);mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y);mPath1.lineTo(mBezierEnd1.x, mBezierEnd1.y);mPath1.lineTo(mTouch.x, mTouch.y);mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y);mPath1.close();GradientDrawable mFolderShadowDrawable;int left;int right;if (mIsRTandLB) {left = (int) (mBezierStart1.x - 1);right = (int) (mBezierStart1.x + f3 + 1);mFolderShadowDrawable = mFolderShadowDrawableLR;} else {left = (int) (mBezierStart1.x - f3 - 1);right = (int) (mBezierStart1.x + 1);mFolderShadowDrawable = mFolderShadowDrawableRL;}canvas.save();canvas.clipPath(mPath0);canvas.clipPath(mPath1, Region.Op.INTERSECT);mPaint.setColorFilter(mColorMatrixFilter);float dis = (float) Math.hypot(mCornerX - mBezierControl1.x,mBezierControl2.y - mCornerY);float f8 = (mCornerX - mBezierControl1.x) / dis;float f9 = (mBezierControl2.y - mCornerY) / dis;mMatrixArray[0] = 1 - 2 * f9 * f9;mMatrixArray[1] = 2 * f8 * f9;mMatrixArray[3] = mMatrixArray[1];mMatrixArray[4] = 1 - 2 * f8 * f8;mMatrix.reset();mMatrix.setValues(mMatrixArray);mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y);mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y);canvas.drawBitmap(bitmap, mMatrix, mPaint);// canvas.drawBitmap(bitmap, mMatrix, null);mPaint.setColorFilter(null);canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y);mFolderShadowDrawable.setBounds(left, (int) mBezierStart1.y, right,(int) (mBezierStart1.y + mMaxLength));mFolderShadowDrawable.draw(canvas);canvas.restore();}public void computeScroll() {super.computeScroll();if (mScroller.computeScrollOffset()) {float x = mScroller.getCurrX();float y = mScroller.getCurrY();mTouch.x = x;mTouch.y = y;postInvalidate();}}private void startAnimation(int delayMillis) {int dx, dy;// dx 水平方向滑动的距离,负值会使滚动向左滚动// dy 垂直方向滑动的距离,负值会使滚动向上滚动if (mCornerX > 0) {dx = -(int) (mWidth + mTouch.x);} else {dx = (int) (mWidth - mTouch.x + mWidth);}if (mCornerY > 0) {dy = (int) (mHeight - mTouch.y);} else {dy = (int) (1 - mTouch.y); // 防止mTouch.y最终变为0}mScroller.startScroll((int) mTouch.x, (int) mTouch.y, dx, dy,delayMillis);}public void abortAnimation() {if (!mScroller.isFinished()) {mScroller.abortAnimation();}}public boolean canDragOver() {if (mTouchToCornerDis > mWidth / 10)return true;return false;}/** * Author : hmg25 Version: 1.0 Description : 是否从左边翻向右边 */public boolean DragToRight() {if (mCornerX > 0)return false;return true;}}

上面关键的地方都写了注释。下面是工程文件下载链接 http://download.csdn.net/detail/jiangxiaoma111/6946137

里面嵌入了一本叫做 遮天 的书,需要换成其他的书本时。不需要改动代码,只需要更改assests文件下的资源,和 strings.xml文件中的对应章节名称和路径即可。



1 0
原创粉丝点击