android 電子書源碼,翻頁效果

這兩天模仿著做瞭一個apk電子書的應用,有翻頁效果,本來是想學一下自己寫的,無奈,最後偷懶使用瞭別人寫的 翻頁類 PageWidget.java

下面是工程文件的結構

這個是寫的類的包結構,PageView.java 類本類是打算自己寫的,然後學習安卓動畫效果,但是由於時間加上懶,再加上看暈瞭,就使用瞭別人寫的PageWidger.java類。來源我忘瞭,當時搜索到的,本來是打算學習的。

好瞭下面,插入代碼:

HomeActivity.javavcD4KPHA+PC9wPgo8cHJlIGNsYXNzPQ==”brush: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;

@Override
protected 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() {
@Override
public 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() {
			@Override
			public boolean onTouch(View v, MotionEvent e) {
				// TODO Auto-generated method stub

				boolean 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);
							} else
								return false;
						} else {
							if (bookpage.nextPage()){
								bookpage.draw(nextCanvas);
							}
							else
								return 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 information
	private 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 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> 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();

		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>();
		pageNum = -1;
		slicePage();
	}

	public Vector getCurPage() {
		return linesVe;
	}

	protected void slicePage() {
		pagesVe.clear();
		int curPos = 0;
		while (curPos < chapterLen) {
			Vector lines = new Vector();
			charBegin = curPos;
			while (lines.size() < lineCount && curPos  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;
				}
				// 如果是把一整段讀取完的話,需要給當前位置加1
				if (paragraphStr.length() == 0)
					curPos += "\n".length();
			}
			pagesVe.add(lines);
		}

	}

	/**
	 * 翻到下一頁
	 */
	public boolean nextPage() {
		if (isLastPage()) {
			if (!nextChapter()) // 如果已經到本書末尾,那麼不能繼續執行翻頁代碼
				return false;
		}
		/*
		 * Vector lines = new Vector(); charBegin = charEnd;
		 * while (lines.size() < lineCount && charEnd  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 lines = new Vector(); String backStr =
		 * content.substring(0, charBegin); charEnd = charBegin;
		 * 
		 * while (lines.size()  0) { int i =
		 * backStr.lastIndexOf("\n"); if(i == -1) i = 0; String paragraphStr =
		 * backStr.substring(i, charBegin); Vector vet = new
		 * Vector(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 = 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);
			else
				c.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;
		else
			timeStr = "" + 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 stub
		mWidth = 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;
		else
			mCornerX = mWidth;
		if (y <= mHeight / 2)
			mCornerY = 0;
		else
			mCornerY = mHeight;

		// 有什麼意思
		if ((mCornerX == 0 && mCornerY == mHeight)
				|| (mCornerX == mWidth && mCornerY == 0))
			mIsRTandLB = true;
		else
			mIsRTandLB = false;
	}

	public boolean doTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		if (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+b
		float a1 = (P2.y - P1.y) / (P2.x - P1.x);
		float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x);

		float a2 = (P4.y - P3.y) / (P4.x - P3.x);
		float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x);
		CrossP.x = (b2 - b1) / (a1 - a2);
		CrossP.y = a1 * CrossP.x + b1;
		return CrossP;
	}

	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  480時
		// 如果繼續翻頁,會出現BUG故在此限制
		if (mTouch.x > 0 && mTouch.x < mWidth) {
			if (mBezierStart1.x  mWidth) {
				if (mBezierStart1.x  " + 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;
	}

	@Override
	protected 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  mMaxLength)
			mCurrentPageShadow
					.setBounds((int) (mBezierControl2.x - 25) - hmg, leftx,
							(int) (mBezierControl2.x + mMaxLength) - hmg,
							rightx);
		else
			mCurrentPageShadow.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文件中的對應章節名稱和路徑即可。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *