Android电子书翻书效果(一)

package Rong;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class PageWidget extends View {

  private static final String TAG = "PageWidget";
  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 mCurPageBackBitmap = 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(480, 800);
  int[] mBackShadowColors;
  int[] mFrontShadowColors;
  GradientDrawable mBackShadowDrawableLR;
  GradientDrawable mBackShadowDrawableRL;
  GradientDrawable mFolderShadowDrawableLR;
  GradientDrawable mFolderShadowDrawableRL;

  GradientDrawable mFrontShadowDrawableHBT;
  GradientDrawable mFrontShadowDrawableHTB;
  GradientDrawable mFrontShadowDrawableVLR;
  GradientDrawable mFrontShadowDrawableVRL;

  private Bitmap mBitmap;
  private Canvas mCanvas;
  private Paint mBitmapPaint;
  Paint paint;

  Paint mPaint;

  public PageWidget(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
  mPath0 = new Path();
  mPath1 = new Path();
  createDrawable();

  mBitmap = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);

  mCanvas = new Canvas(mBitmap);
  mBitmapPaint = new Paint(Paint.DITHER_FLAG);

  paint = new Paint();
  mPaint = new Paint();
  mPaint.setStyle(Paint.Style.FILL);

  mCurPageBitmap = BitmapFactory.decodeResource(this.getResources(),
      R.drawable.page1);
  mNextPageBitmap = BitmapFactory.decodeResource(this.getResources(),
      R.drawable.page2);

  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();
  }

 
  private 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;
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
  // TODO Auto-generated method stub
  if (event.getAction() == MotionEvent.ACTION_MOVE) {//手指移动
    mCanvas.drawColor(0xFFAAAAAA);
    mTouch.x = event.getX();
    mTouch.y = event.getY();
    this.postInvalidate();//更新视图
  }
  if (event.getAction() == MotionEvent.ACTION_DOWN) {//手指按下
    mCanvas.drawColor(0xFFAAAAAA);
    mTouch.x = event.getX();
    mTouch.y = event.getY();
    calcCornerXY(mTouch.x, mTouch.y);
    this.postInvalidate();
  }
  if (event.getAction() == MotionEvent.ACTION_UP) {//手指松开
    mCanvas.drawColor(0xFFAAAAAA);
    mTouch.x = mCornerX;
    mTouch.y = mCornerY;
    this.postInvalidate();
  }
  return true;
  }

 
  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(TAG, "mTouchX  " + mTouch.x + "  mTouchY  " + mTouch.y);
  Log.i(TAG, "mBezierControl1.x  " + mBezierControl1.x
      + "  mBezierControl1.y  " + mBezierControl1.y);
  Log.i(TAG, "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 (mBezierStart1.x < 0 || mBezierStart1.x > 480) { 
    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(TAG, "mTouchX --> " + mTouch.x + "  mTouchY-->  "
        + mTouch.y);
    Log.i(TAG, "mBezierControl1.x--  " + mBezierControl1.x
        + "  mBezierControl1.y -- " + mBezierControl1.y);
    Log.i(TAG, "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(TAG, "mBezierEnd1.x  " + mBezierEnd1.x + "  mBezierEnd1.y  "
      + mBezierEnd1.y);
  Log.i(TAG, "mBezierEnd2.x  " + mBezierEnd2.x + "  mBezierEnd2.y  "
      + mBezierEnd2.y);

 
  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 drawNextPageAreaAndShado w(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, Bitmap bm3) {
  mCurPageBitmap = bm1;
  mCurPageBackBitmap = bm2;
  mNextPageBitmap = bm3;
  }

  @Override
  protected void onDraw(Canvas canvas) {
  canvas.drawColor(0xFFAAAAAA);
  calcPoints();
  drawCurrentPageArea(mCanvas, mCurPageBitmap, mPath0);
  drawNextPageAreaAndShado w(mCanvas, mNextPageBitmap);
  drawCurrentPageShadow(mCanvas);
  drawCurrentBackArea(mCanvas, mCurPageBitmap);
  canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
  }

 
  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);
  }

 
  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 - 800;
  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(TAG, "mBezierControl2.x    " + mBezierControl2.x
      + "  mBezierControl2.y  " + mBezierControl2.y);
  mCurrentPageShadow.draw(canvas);
  canvas.restore();
  }

 
  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);
  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();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值