編輯:關於Android編程
這兩天模仿著做了一個apk電子書的應用,有翻頁效果,本來是想學一下自己寫的,無奈,最後偷懶使用了別人寫的 翻頁類 PageWidget.java
下面是工程文件的結構
這個是寫的類的包結構,PageView.java 類本類是打算自己寫的,然後學習安卓動畫效果,但是由於時間加上懶,再加上看暈了,就使用了別人寫的PageWidger.java類。來源我忘了,當時搜索到的,本來是打算學習的。
好了下面,插入代碼:
HomeActivity.java<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+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); } }
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 VectorlinesVe; // 將章節內容分成行,並將每頁按行存儲到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 > 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 >(); 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 < 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; } // 如果是把一整段讀取完的話,需要給當前位置加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 < 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 lines = new Vector (); 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 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 <= 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); 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); } }
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 < 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; } @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 < 0) temp = mBezierControl2.y - mHeight; else temp = 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); 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文件中的對應章節名稱和路徑即可。
完美解決解決Android使用Zxing掃描二維碼改成豎屏後,後面的預覽畫面出現了拉伸,扭曲的情況第一步:找到com.zxing.camera包下的CameraConf
AsyncTask,是android提供的輕量級的異步類,可以直接繼承AsyncTask,在類中實現異步操作,並提供接口反饋當前異步執行的程度(可以通過接口實現UI進度更
如果你使用的是小米手機或者MIUI系統,你知道MIUI系統的撥號界面可以直接查詢你的手機話費余額嗎?這麼高大上的功能沒用過吧?還在撥打客服熱線、發送短信查詢
一.概述代理模式也是平時比較常用的設計模式之一,代理模式其實就是提供了一個新的對象,實現了對真實對象的操作,或成為真實對象的替身.在日常生活中也是很常見的.例如A要租房,