Android書籍翻頁效果

y37f 9年前發布 | 2K 次閱讀 Java 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;
    }

}

源代碼下載地址

 本文由用戶 y37f 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!