Android书籍翻页效果
模仿此效果,只需要 导入一下文件即可 :BookActivity.java,BookPageFactory.java,PageWidget.java
package com.andorid.shu.love; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.Display; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.Toast; import com.sqlite.DbHelper; public class BookActivity extends Activity { /** Called when the activity is first created. */ public final static int OPENMARK = 0; public final static int SAVEMARK = 1; public final static int TEXTSET = 2; private PageWidget mPageWidget; private Bitmap mCurPageBitmap, mNextPageBitmap; private Canvas mCurPageCanvas, mNextPageCanvas; private BookPageFactory pagefactory; private static Boolean isExit = false;//用于判断是否推出 private static Boolean hasTask = false; private int whichSize=6;//当前的字体大小 private int txtProgress = 0;//当前阅读的进度 private String txtPath = "/sdcard/lovereader/百年孤独.txt"; private String bookPath = "/sdcard/lovereader/"; final String[] font = new String[] {"20","24","26","30","32","36", "40","46","50","56","60","66","70"}; int curPostion; DbHelper db; Context mContext; Cursor mCursor; BookInfo book = null; SetupInfo setup = null; //add for 2015-03-04 private int[] mPics = new int [] {R.drawable.c0,R.drawable.c1,R.drawable.c2,R.drawable.c3}; private int mCurrent = 0; private int mNext = 1; //add for 2015-03-06 private List<String> mFileList = new ArrayList<String>(); private static final String TAG = "BookActivity"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /*requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);*/ Display display = getWindowManager().getDefaultDisplay(); int w = display.getWidth(); int h = display.getHeight(); System.out.println(w + "\t" + h); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;//图片大小,设置越大,图片越不清晰,占用空间越小 /*String SDPath = getSDPath(); Log.d(TAG, "sdPath:"+SDPath);*/ ///getFile(new File("/storage/extSdCard/pic/pic_1")); //get FileDirPath String dirPath = getIntent().getStringExtra("...."); dirPath = "/storage/extSdCard/pic/pic_1"; File mFile = new File(dirPath); if(mFile.exists()){ if(mFile.isDirectory()){ if(mFile.listFiles().length==0){ Toast.makeText(this, "文件不存在!", Toast.LENGTH_SHORT).show(); return; } } } try { //获取文件夹下的所有图片路径 填充mFileList集合 getFile(mFile); } catch (IOException e2) { // TODO Auto-generated catch block e2.printStackTrace(); } pagefactory = new BookPageFactory(w, h,mFileList); mCurPageBitmap = BitmapFactory.decodeFile(mFileList.get(mCurrent), options); mNextPageBitmap = BitmapFactory.decodeFile(mFileList.get(mNext), options); mCurPageBitmap = pagefactory.resizePic(mCurPageBitmap, w, h); mNextPageBitmap = pagefactory.resizePic(mNextPageBitmap, w, h); mContext = this; mPageWidget = new PageWidget(this, w, h); setContentView(mPageWidget); mPageWidget.setBitmaps(mCurPageBitmap, mNextPageBitmap); mPageWidget.setOnTouchListener(new OnTouchListener() { @Override 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()); //int temp = mCurrent!=0?mCurrent-1:0; //获取当前页 mCurPageBitmap = pagefactory.getPage(mCurrent); Log.d(TAG, "---当前页:mCurrentPic:"+mCurrent); Log.d(TAG, "---当前页:路径:"+mFileList.get(mCurrent)); if (mPageWidget.DragToRight()) { if (pagefactory.isfirstPage()){ Toast.makeText(mContext, "已经是第一页",Toast.LENGTH_SHORT).show(); return false; } //获取当前页坐标 mCurrent = mCurrent > 0?--mCurrent:0; Log.d(TAG, "mCurrentPic:"+mCurrent); mNextPageBitmap = pagefactory.prePage(mCurrent); Log.d(TAG, "---下一页:路径:"+mFileList.get(mCurrent)); } else { if (pagefactory.islastPage()){ Toast.makeText(mContext, "已经是最后一页",Toast.LENGTH_SHORT).show(); return false; } mCurrent = mCurrent < mFileList.size()-1 ?++mCurrent:mFileList.size()-1; Log.d(TAG, "mCurrentPic:"+mCurrent); Log.d(TAG, "---下一页:路径:"+mFileList.get(mCurrent)); mNextPageBitmap = pagefactory.nextPage(mCurrent); } mPageWidget.setBitmaps(mCurPageBitmap, mNextPageBitmap); } ret = mPageWidget.doTouchEvent(e); return ret; } return false; } }); } public String getSDPath(){ File sdDir = null; boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在 if(sdCardExist){ sdDir = Environment.getExternalStorageDirectory();//获取跟目录 } return sdDir.toString(); } /** * 获取文件对象 * @param file * @return * @throws IOException */ public List<String> getFile(File file) throws IOException{ // Log.d(TAG, "getFile.fun..start.."); File[] fileArray =file.listFiles(); // Log.d(TAG, "getFile.fun..listFiles.."); for (File f : fileArray) { // Log.d(TAG, "getFile.fun..ffff.."); if(f.isFile()){ // Log.d(TAG, "getFile.fun..adddd..11111.."); mFileList.add(f.getCanonicalPath()); // Log.d(TAG, "getFile.fun..adddd.."); }else{ getFile(f); // Log.d(TAG, "getFile.run..again.."); } } // Log.d(TAG, "getFile.fun..finsh.."); return mFileList; } }
修改 BookActivity.java dirPath 路径即可
BookPageFactory.java
package com.andorid.shu.love; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Vector; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Align; public class BookPageFactory { private File book_file = null; private MappedByteBuffer m_mbBuf = null; private int m_mbBufLen = 0; private int m_mbBufBegin = 50; //50 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 = 40; private int r_fontSize = 30; private int m_textColor = Color.BLACK; private int m_backColor = 0xffff9e85; // 背景颜色 private int marginWidth = 15; // 左右与边缘的距离 private int marginHeight = 20; // 上下与边缘的距离 private int youmiHeight = 0;//广告条的狂度 private int mLineCount; // 每页可以显示的行数 private float mVisibleHeight; // 绘制内容的宽 private float mVisibleWidth; // 绘制内容的宽 private boolean m_isfirstPage, m_islastPage; private int b_FontSize = 16;//底部文字大小 private int e_fontSize = 5; private int spaceSize = 20;//行间距大小 private int curProgress = 0;//当前的进度 private String fileName = ""; // private int m_nLineSpaceing = 5; private Paint mPaint; private Paint bPaint;//底部文字绘制 private Paint spactPaint;//行间距绘制 private Paint titlePaint;//标题绘制 //add for 2015 03 06 private List<String> mFileList;//当前文件列表 public BookPageFactory(int w, int h,List<String> fileList) { // TODO Auto-generated constructor stub mWidth = w; mHeight = h; //add for 2015 03 04 this.mFileList = fileList; } //add for 2015 03 04 public Bitmap prePage(int currentNum){ this.m_islastPage = false; if(currentNum == 0){ //currentNum = 0; this.m_isfirstPage = true; }else{ //currentNum--; this.m_isfirstPage = false; } BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;//图片大小,设置越大,图片越不清晰,占用空间越小 Bitmap bitmap = BitmapFactory.decodeFile(mFileList.get(currentNum), options); //Bitmap bitmap = BitmapFactory.decodeResource(this.mResources, mPics[currentNum]); //图片放大至屏幕大小 bitmap = resizePic(bitmap, mWidth, mHeight); return bitmap; } //add for 2015 03 04 public Bitmap nextPage(int currentNum){ this.m_isfirstPage = false; if(currentNum >= mFileList.size()-1){ //currentNum = mPics.length-1; this.m_islastPage = true; }else{ //currentNum++; this.m_islastPage = false; } BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;//图片大小,设置越大,图片越不清晰,占用空间越小 Bitmap bitmap = BitmapFactory.decodeFile(mFileList.get(currentNum), options); //Bitmap bitmap = BitmapFactory.decodeResource(this.mResources, mPics[currentNum]); //图片放大至屏幕大小 bitmap = resizePic(bitmap, mWidth, mHeight); return bitmap; } //add for 2015 03 06 public Bitmap getPage(int currnet){ BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;//图片大小,设置越大,图片越不清晰,占用空间越小 Bitmap bitmap = BitmapFactory.decodeFile(mFileList.get(currnet), options); //Bitmap bitmap = BitmapFactory.decodeResource(this.mResources, mPics[currnet]); //图片放大至屏幕大小 bitmap = resizePic(bitmap, mWidth, mHeight); return bitmap; } //add for 2015 03 06 public static Bitmap resizePic(Bitmap bitmap, int screenWidth,int screenHight) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix matrix = new Matrix(); float scale = (float) screenWidth / w; float scale2 = (float) screenHight / h; // scale = scale < scale2 ? scale : scale2; matrix.postScale(scale, scale2); Bitmap bmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); if (bitmap != null && !bitmap.equals(bmp) && !bitmap.isRecycled()) { bitmap.recycle(); bitmap = null; } return bmp; } private static double round1(double v, int scale) { if (scale < 0) return v; String temp = "#####0."; for (int i = 0; i < scale; i++) { temp += "0"; } return Double.valueOf(new java.text.DecimalFormat(temp).format(v)); } public void setBgBitmap(Bitmap BG) { if (BG.getWidth() != mWidth || BG.getHeight() != mHeight) m_book_bg = Bitmap.createScaledBitmap(BG, mWidth, mHeight, true); else m_book_bg = BG; } public boolean isfirstPage() { return m_isfirstPage; } public void setIslastPage(boolean islast){ m_islastPage = islast; } public boolean islastPage() { return m_islastPage; } public int getCurPostion() { return m_mbBufEnd; } public int getCurPostionBeg(){ return m_mbBufBegin; } public void setBeginPos(int pos) { m_mbBufEnd = pos; m_mbBufBegin = pos; } public int getBufLen() { return m_mbBufLen; } public int getCurProgress(){ return curProgress; } public String getOneLine() { return m_lines.toString().substring(0, 10); } public void changBackGround(int color) { mPaint.setColor(color); } public void setFontSize(int size) { m_fontSize = size; mPaint.setTextSize(size); int totalSize = m_fontSize+spaceSize; mLineCount = (int) (mVisibleHeight / totalSize); // 可显示的行数 } public void setFileName(String fileName){ fileName = fileName.substring(0,fileName.indexOf(".")); this.fileName = fileName; } }
PageWidget.java
package com.andorid.shu.love; 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 static final String TAG = "hmg"; private int mWidth = 480; private int mHeight = 800; 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; } }