diff --git a/app/src/main/java/com/novel/read/widget/page/anim/CoverPageAnim.kt b/app/src/main/java/com/novel/read/widget/page/anim/CoverPageAnim.kt index 2a2795c..216a893 100644 --- a/app/src/main/java/com/novel/read/widget/page/anim/CoverPageAnim.kt +++ b/app/src/main/java/com/novel/read/widget/page/anim/CoverPageAnim.kt @@ -15,13 +15,11 @@ import com.novel.read.widget.page.PageAnimation class CoverPageAnim(w: Int, h: Int, view: View, listener: PageAnimation.OnPageChangeListener) : HorizonPageAnim(w, h, view, listener) { - private val mSrcRect: Rect - private val mDestRect: Rect + private val mSrcRect: Rect = Rect(0, 0, mViewWidth, mViewHeight) + private val mDestRect: Rect = Rect(0, 0, mViewWidth, mViewHeight) private val mBackShadowDrawableLR: GradientDrawable init { - mSrcRect = Rect(0, 0, mViewWidth, mViewHeight) - mDestRect = Rect(0, 0, mViewWidth, mViewHeight) val mBackShadowColors = intArrayOf(0x66000000, 0x00000000) mBackShadowDrawableLR = GradientDrawable( GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors diff --git a/app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.java b/app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.java deleted file mode 100644 index 8df5eac..0000000 --- a/app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.novel.read.widget.page.anim; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; - -import com.novel.read.widget.page.PageAnimation; - -/** - * Created by zlj - * 横向动画 - */ - -public abstract class HorizonPageAnim extends PageAnimation { - private static final String TAG = "HorizonPageAnim"; - - protected Bitmap mCurBitmap; - protected Bitmap mNextBitmap; - //是否取消翻页 - protected boolean isCancel = false; - - //可以使用 mLast代替 - private int mMoveX = 0; - private int mMoveY = 0; - //是否移动了 - private boolean isMove = false; - //是否翻阅下一页。true表示翻到下一页,false表示上一页。 - private boolean isNext = false; - - //是否没下一页或者上一页 - private boolean noNext = false; - - public HorizonPageAnim(int w, int h, View view, OnPageChangeListener listener) { - this(w, h, 0, 0, view, listener); - } - - public HorizonPageAnim(int w, int h, int marginWidth, int marginHeight, - View view, OnPageChangeListener listener) { - super(w, h, marginWidth, marginHeight, view,listener); - //创建图片 - mCurBitmap = Bitmap.createBitmap(mViewWidth, mViewHeight, Bitmap.Config.RGB_565); - mNextBitmap = Bitmap.createBitmap(mViewWidth, mViewHeight, Bitmap.Config.RGB_565); - } - - /** - * 转换页面,在显示下一章的时候,必须首先调用此方法 - */ - public void changePage(){ - Bitmap bitmap = mCurBitmap; - mCurBitmap = mNextBitmap; - mNextBitmap = bitmap; - } - - public abstract void drawStatic(Canvas canvas); - - public abstract void drawMove(Canvas canvas); - - @Override - public boolean onTouchEvent(MotionEvent event) { - //获取点击位置 - int x = (int)event.getX(); - int y = (int)event.getY(); - //设置触摸点 - setTouchPoint(x,y); - - switch (event.getAction()){ - case MotionEvent.ACTION_DOWN: - //移动的点击位置 - mMoveX = 0; - mMoveY = 0; - //是否移动 - isMove = false; - //是否存在下一章 - noNext = false; - //是下一章还是前一章 - isNext = false; - //是否正在执行动画 - isRunning = false; - //取消 - isCancel = false; - //设置起始位置的触摸点 - setStartPoint(x,y); - //如果存在动画则取消动画 - abortAnim(); - break; - case MotionEvent.ACTION_MOVE: - final int slop = ViewConfiguration.get(mView.getContext()).getScaledTouchSlop(); - //判断是否移动了 - if (!isMove) { - isMove = Math.abs(mStartX - x) > slop || Math.abs(mStartY - y) > slop; - } - - if (isMove){ - //判断是否是准备移动的状态(将要移动但是还没有移动) - if (mMoveX == 0 && mMoveY ==0) { - //判断翻得是上一页还是下一页 - if (x - mStartX > 0){ - //上一页的参数配置 - isNext = false; - boolean hasPrev = mListener.hasPrev(); - setDirection(Direction.PRE); - //如果上一页不存在 - if (!hasPrev) { - noNext = true; - return true; - } - }else{ - //进行下一页的配置 - isNext = true; - //判断是否下一页存在 - boolean hasNext = mListener.hasNext(); - //如果存在设置动画方向 - setDirection(Direction.NEXT); - - //如果不存在表示没有下一页了 - if (!hasNext) { - noNext = true; - return true; - } - } - }else{ - //判断是否取消翻页 - if (isNext){ - if (x - mMoveX > 0){ - isCancel = true; - }else { - isCancel = false; - } - }else{ - if (x - mMoveX < 0){ - isCancel = true; - }else { - isCancel = false; - } - } - } - - mMoveX = x; - mMoveY = y; - isRunning = true; - mView.invalidate(); - } - break; - case MotionEvent.ACTION_UP: - if (!isMove){ - if (x < mScreenWidth / 2){ - isNext = false; - }else{ - isNext = true; - } - - if (isNext) { - //判断是否下一页存在 - boolean hasNext = mListener.hasNext(); - //设置动画方向 - setDirection(Direction.NEXT); - if (!hasNext) { - return true; - } - } else { - boolean hasPrev = mListener.hasPrev(); - setDirection(Direction.PRE); - if (!hasPrev) { - return true; - } - } - } - - // 是否取消翻页 - if (isCancel){ - mListener.pageCancel(); - } - - // 开启翻页效果 - if (!noNext) { - startAnim(); - mView.invalidate(); - } - break; - } - return true; - } - - @Override - public void draw(Canvas canvas) { - if (isRunning) { - drawMove(canvas); - } else { - if (isCancel){ - mNextBitmap = mCurBitmap.copy(Bitmap.Config.RGB_565, true); - } - drawStatic(canvas); - } - } - - @Override - public void scrollAnim() { - if (mScroller.computeScrollOffset()) { - int x = mScroller.getCurrX(); - int y = mScroller.getCurrY(); - - setTouchPoint(x, y); - - if (mScroller.getFinalX() == x && mScroller.getFinalY() == y){ - isRunning = false; - } - mView.postInvalidate(); - } - } - - @Override - public void abortAnim() { - if (!mScroller.isFinished()){ - mScroller.abortAnimation(); - isRunning = false; - setTouchPoint(mScroller.getFinalX(),mScroller.getFinalY()); - mView.postInvalidate(); - } - } - - @Override - public Bitmap getBgBitmap() { - return mNextBitmap; - } - - @Override - public Bitmap getNextBitmap() { - return mNextBitmap; - } -} diff --git a/app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.kt b/app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.kt new file mode 100644 index 0000000..4ac0243 --- /dev/null +++ b/app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.kt @@ -0,0 +1,223 @@ +package com.novel.read.widget.page.anim + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.view.MotionEvent +import android.view.View +import android.view.ViewConfiguration + +import com.novel.read.widget.page.PageAnimation + +/** + * Created by zlj + * 横向动画 + */ + +abstract class HorizonPageAnim( + w: Int, h: Int, marginWidth: Int, marginHeight: Int, + view: View, listener: PageAnimation.OnPageChangeListener +) : PageAnimation(w, h, marginWidth, marginHeight, view, listener) { + + protected var mCurBitmap: Bitmap + protected var mNextBitmap: Bitmap + //是否取消翻页 + protected var isCancel = false + + //可以使用 mLast代替 + private var mMoveX = 0 + private var mMoveY = 0 + //是否移动了 + private var isMove = false + //是否翻阅下一页。true表示翻到下一页,false表示上一页。 + private var isNext = false + + //是否没下一页或者上一页 + private var noNext = false + + constructor(w: Int, h: Int, view: View, listener: PageAnimation.OnPageChangeListener) : this( + w, + h, + 0, + 0, + view, + listener + ) + + init { + //创建图片 + mCurBitmap = Bitmap.createBitmap(mViewWidth, mViewHeight, Bitmap.Config.RGB_565) + mNextBitmap = Bitmap.createBitmap(mViewWidth, mViewHeight, Bitmap.Config.RGB_565) + } + + /** + * 转换页面,在显示下一章的时候,必须首先调用此方法 + */ + fun changePage() { + val bitmap = mCurBitmap + mCurBitmap = mNextBitmap + mNextBitmap = bitmap + } + + abstract fun drawStatic(canvas: Canvas) + + abstract fun drawMove(canvas: Canvas) + + override fun onTouchEvent(event: MotionEvent): Boolean { + //获取点击位置 + val x = event.x.toInt() + val y = event.y.toInt() + //设置触摸点 + setTouchPoint(x.toFloat(), y.toFloat()) + + when (event.action) { + MotionEvent.ACTION_DOWN -> { + //移动的点击位置 + mMoveX = 0 + mMoveY = 0 + //是否移动 + isMove = false + //是否存在下一章 + noNext = false + //是下一章还是前一章 + isNext = false + //是否正在执行动画 + isRunning = false + //取消 + isCancel = false + //设置起始位置的触摸点 + setStartPoint(x.toFloat(), y.toFloat()) + //如果存在动画则取消动画 + abortAnim() + } + MotionEvent.ACTION_MOVE -> { + val slop = ViewConfiguration.get(mView.context).scaledTouchSlop + //判断是否移动了 + if (!isMove) { + isMove = Math.abs(mStartX - x) > slop || Math.abs(mStartY - y) > slop + } + + if (isMove) { + //判断是否是准备移动的状态(将要移动但是还没有移动) + if (mMoveX == 0 && mMoveY == 0) { + //判断翻得是上一页还是下一页 + if (x - mStartX > 0) { + //上一页的参数配置 + isNext = false + val hasPrev = mListener.hasPrev() + direction = PageAnimation.Direction.PRE + //如果上一页不存在 + if (!hasPrev) { + noNext = true + return true + } + } else { + //进行下一页的配置 + isNext = true + //判断是否下一页存在 + val hasNext = mListener.hasNext() + //如果存在设置动画方向 + direction = PageAnimation.Direction.NEXT + + //如果不存在表示没有下一页了 + if (!hasNext) { + noNext = true + return true + } + } + } else { + //判断是否取消翻页 + if (isNext) { + isCancel = x - mMoveX > 0 + } else { + isCancel = x - mMoveX < 0 + } + } + + mMoveX = x + mMoveY = y + isRunning = true + mView.invalidate() + } + } + MotionEvent.ACTION_UP -> { + if (!isMove) { + isNext = x >= mScreenWidth / 2 + + if (isNext) { + //判断是否下一页存在 + val hasNext = mListener.hasNext() + //设置动画方向 + direction = PageAnimation.Direction.NEXT + if (!hasNext) { + return true + } + } else { + val hasPrev = mListener.hasPrev() + direction = PageAnimation.Direction.PRE + if (!hasPrev) { + return true + } + } + } + + // 是否取消翻页 + if (isCancel) { + mListener.pageCancel() + } + + // 开启翻页效果 + if (!noNext) { + startAnim() + mView.invalidate() + } + } + } + return true + } + + override fun draw(canvas: Canvas) { + if (isRunning) { + drawMove(canvas) + } else { + if (isCancel) { + mNextBitmap = mCurBitmap.copy(Bitmap.Config.RGB_565, true) + } + drawStatic(canvas) + } + } + + override fun scrollAnim() { + if (mScroller.computeScrollOffset()) { + val x = mScroller.currX + val y = mScroller.currY + + setTouchPoint(x.toFloat(), y.toFloat()) + + if (mScroller.finalX == x && mScroller.finalY == y) { + isRunning = false + } + mView.postInvalidate() + } + } + + override fun abortAnim() { + if (!mScroller.isFinished) { + mScroller.abortAnimation() + isRunning = false + setTouchPoint(mScroller.finalX.toFloat(), mScroller.finalY.toFloat()) + mView.postInvalidate() + } + } + + override fun getBgBitmap(): Bitmap { + return mNextBitmap + } + + override fun getNextBitmap(): Bitmap { + return mNextBitmap + } + + companion object { + private val TAG = "HorizonPageAnim" + } +} diff --git a/app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.java b/app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.java deleted file mode 100644 index 9043830..0000000 --- a/app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.java +++ /dev/null @@ -1,655 +0,0 @@ -package com.novel.read.widget.page.anim; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -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.os.Build; -import android.view.View; - -/** - * Created by zlj - * 仿真动画 - */ - -public class SimulationPageAnim extends HorizonPageAnim { - private static final String TAG = "SimulationPageAnim"; - - private int mCornerX = 1; // 拖拽点对应的页脚 - private int mCornerY = 1; - private Path mPath0; - private Path mPath1; - - 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; // 是否属于右上左下 - private float mMaxLength ; - private int[] mBackShadowColors;// 背面颜色组 - private int[] mFrontShadowColors;// 前面颜色组 - private GradientDrawable mBackShadowDrawableLR; // 有阴影的GradientDrawable - private GradientDrawable mBackShadowDrawableRL; - private GradientDrawable mFolderShadowDrawableLR; - private GradientDrawable mFolderShadowDrawableRL; - - private GradientDrawable mFrontShadowDrawableHBT; - private GradientDrawable mFrontShadowDrawableHTB; - private GradientDrawable mFrontShadowDrawableVLR; - private GradientDrawable mFrontShadowDrawableVRL; - - Paint mPaint; - public SimulationPageAnim(int w, int h, View view, OnPageChangeListener listener) { - super(w, h, view, listener); - mPath0 = new Path(); - mPath1 = new Path(); - mMaxLength = (float) Math.hypot(mScreenWidth, mScreenHeight); - mPaint = new Paint(); - - mPaint.setStyle(Paint.Style.FILL); - - createDrawable(); - - ColorMatrix cm = new ColorMatrix();//设置颜色数组 - float array[] = { 1, 0, 0, 0, 0, - 0, 1, 0, 0, 0, - 0, 0,1, 0, 0, - 0, 0, 0, 1, 0 }; - cm.set(array); - mColorMatrixFilter = new ColorMatrixColorFilter(cm); - mMatrix = new Matrix(); - - mTouchX = 0.01f; // 不让x,y为0,否则在点计算时会有问题 - mTouchY = 0.01f; - } - - @Override - public void drawMove(Canvas canvas) { - switch (mDirection){ - case NEXT: - calcPoints(); - drawCurrentPageArea(canvas, mCurBitmap, mPath0); - drawNextPageAreaAndShadow(canvas, mNextBitmap); - drawCurrentPageShadow(canvas); - drawCurrentBackArea(canvas, mCurBitmap); - break; - default: - calcPoints(); - drawCurrentPageArea(canvas, mNextBitmap, mPath0); - drawNextPageAreaAndShadow(canvas, mCurBitmap); - drawCurrentPageShadow(canvas); - drawCurrentBackArea(canvas, mNextBitmap); - break; - } - } - - @Override - public void drawStatic(Canvas canvas) { - if (isCancel){ - mNextBitmap = mCurBitmap.copy(Bitmap.Config.RGB_565, true); - canvas.drawBitmap(mCurBitmap, 0, 0, null); - }else { - canvas.drawBitmap(mNextBitmap, 0, 0, null); - } - } - - @Override - public void startAnim() { - super.startAnim(); - int dx, dy; - // dx 水平方向滑动的距离,负值会使滚动向左滚动 - // dy 垂直方向滑动的距离,负值会使滚动向上滚动 - if (isCancel){ - - if (mCornerX > 0 && mDirection.equals(Direction.NEXT)) { - dx = (int) (mScreenWidth - mTouchX); - } else { - dx = -(int) mTouchX; - } - - if (!mDirection.equals(Direction.NEXT)){ - dx = (int) - (mScreenWidth + mTouchX); - } - - if (mCornerY > 0) { - dy = (int) (mScreenHeight - mTouchY); - } else { - dy = - (int) mTouchY; // 防止mTouchY最终变为0 - } - }else { - if (mCornerX > 0 && mDirection.equals(Direction.NEXT)) { - dx = -(int) (mScreenWidth + mTouchX); - } else { - dx = (int) (mScreenWidth - mTouchX + mScreenWidth); - } - if (mCornerY > 0) { - dy = (int) (mScreenHeight - mTouchY); - } else { - dy = (int) (1 - mTouchY); // 防止mTouchY最终变为0 - } - } - mScroller.startScroll((int) mTouchX, (int) mTouchY, dx, dy, 400); - } - - @Override - public void setDirection(Direction direction) { - super.setDirection(direction); - - switch (direction){ - case PRE: - //上一页滑动不出现对角 - if (mStartX > mScreenWidth / 2){ - calcCornerXY(mStartX,mScreenHeight); - }else{ - calcCornerXY(mScreenWidth - mStartX,mScreenHeight); - } - break; - case NEXT: - if (mScreenWidth / 2 > mStartX){ - calcCornerXY(mScreenWidth - mStartX,mStartY); - } - break; - } - } - - @Override - public void setStartPoint(float x, float y) { - super.setStartPoint(x, y); - calcCornerXY(x,y); - } - - @Override - public void setTouchPoint(float x, float y) { - super.setTouchPoint(x, y); - //触摸y中间位置吧y变成屏幕高度 - if ((mStartY > mScreenHeight / 3 && mStartY < mScreenHeight * 2 / 3) || mDirection.equals(Direction.PRE)){ - mTouchY = mScreenHeight; - } - - if (mStartY > mScreenHeight / 3 && mStartY < mScreenHeight / 2 && mDirection.equals(Direction.NEXT)){ - mTouchY = 1; - } - } - - /** - * 创建阴影的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); - } - - /** - * 是否能够拖动过去 - * - * @return - */ - public boolean canDragOver() { - if (mTouchToCornerDis > mScreenWidth / 10) - return true; - return false; - } - - public boolean right() { - if (mCornerX > -4) - return false; - return true; - } - - /** - * 绘制翻起页背面 - * - * @param canvas - * @param bitmap - */ - 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(mTouchX, mTouchY); - 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(); - try { - canvas.clipPath(mPath0); - if(Build.VERSION.SDK_INT >= 28){ - canvas.clipPath(mPath1); - }else { - canvas.clipPath(mPath1, Region.Op.INTERSECT); - } - } catch (Exception e) { - } - - mPaint.setColorFilter(mColorMatrixFilter); - //对Bitmap进行取色 - int color = bitmap.getPixel(1, 1); - //获取对应的三色 - int red = (color & 0xff0000) >> 16; - int green = (color & 0x00ff00) >> 8; - int blue = (color & 0x0000ff); - //转换成含有透明度的颜色 - int tempColor = Color.argb(200, red, green, blue); - - - 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.drawColor(tempColor); - - 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(); - } - - /** - * 绘制翻起页的阴影 - * - * @param canvas - */ - public void drawCurrentPageShadow(Canvas canvas) { - double degree; - if (mIsRTandLB) { - degree = Math.PI - / 4 - - Math.atan2(mBezierControl1.y - mTouchY, mTouchX - - mBezierControl1.x); - } else { - degree = Math.PI - / 4 - - Math.atan2(mTouchY - mBezierControl1.y, mTouchX - - mBezierControl1.x); - } - // 翻起页阴影顶点与touch点的距离 - double d1 = (float) 25 * 1.414 * Math.cos(degree); - double d2 = (float) 25 * 1.414 * Math.sin(degree); - float x = (float) (mTouchX + d1); - float y; - if (mIsRTandLB) { - y = (float) (mTouchY + d2); - } else { - y = (float) (mTouchY - d2); - } - mPath1.reset(); - mPath1.moveTo(x, y); - mPath1.lineTo(mTouchX, mTouchY); - mPath1.lineTo(mBezierControl1.x, mBezierControl1.y); - mPath1.lineTo(mBezierStart1.x, mBezierStart1.y); - mPath1.close(); - float rotateDegrees; - canvas.save(); - try { - - if(Build.VERSION.SDK_INT >= 28){ - canvas.clipOutPath(mPath0); - canvas.clipPath(mPath1); - }else { - canvas.clipPath(mPath0, Region.Op.XOR); - canvas.clipPath(mPath1, Region.Op.INTERSECT); - - } - - } catch (Exception e) { - // TODO: handle exception - } - - 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(mTouchX - - mBezierControl1.x, mBezierControl1.y - mTouchY)); - 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(mTouchX, mTouchY); - mPath1.lineTo(mBezierControl2.x, mBezierControl2.y); - mPath1.lineTo(mBezierStart2.x, mBezierStart2.y); - mPath1.close(); - canvas.save(); - try { - if(Build.VERSION.SDK_INT >= 28){ - canvas.clipOutPath(mPath0); - canvas.clipPath(mPath1); - }else { - canvas.clipPath(mPath0, Region.Op.XOR); - canvas.clipPath(mPath1, Region.Op.INTERSECT); - } - } catch (Exception e) { - } - - 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 - - mTouchY, mBezierControl2.x - mTouchX)); - canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y); - float temp; - if (mBezierControl2.y < 0) - temp = mBezierControl2.y - mScreenHeight; - 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); - - mCurrentPageShadow.draw(canvas); - 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(); - try { - - if(Build.VERSION.SDK_INT >= 28){ - canvas.clipPath(mPath0); - canvas.clipPath(mPath1); - }else { - canvas.clipPath(mPath0); - canvas.clipPath(mPath1, Region.Op.INTERSECT); - } - } catch (Exception e) { - } - - - canvas.drawBitmap(bitmap, 0, 0, null); - canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y); - mBackShadowDrawable.setBounds(leftx, (int) mBezierStart1.y, rightx, - (int) (mMaxLength + mBezierStart1.y));//左上及右下角的xy坐标值,构成一个矩形 - mBackShadowDrawable.draw(canvas); - canvas.restore(); - } - - 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(mTouchX, mTouchY); - mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y); - mPath0.quadTo(mBezierControl2.x, mBezierControl2.y, mBezierStart2.x, - mBezierStart2.y); - mPath0.lineTo(mCornerX, mCornerY); - mPath0.close(); - - canvas.save(); -// if(Build.VERSION.SDK_INT >= 28){ -// canvas.clipOutPath(path); -// }else { -// canvas.clipPath(path, Region.Op.XOR); -// } - canvas.drawBitmap(bitmap, 0, 0, null); - try { - canvas.restore(); - } catch (Exception e) { - - } - - } - - /** - * 计算拖拽点对应的拖拽脚 - * - * @param x - * @param y - */ - public void calcCornerXY(float x, float y) { - if (x <= mScreenWidth / 2) { - mCornerX = 0; - }else { - mCornerX = mScreenWidth; - } - if (y <= mScreenHeight / 2) { - mCornerY = 0; - } else { - mCornerY = mScreenHeight; - } - - if ((mCornerX == 0 && mCornerY == mScreenHeight) - || (mCornerX == mScreenWidth && mCornerY == 0)) { - mIsRTandLB = true; - }else { - mIsRTandLB = false; - } - - } - - private void calcPoints() { - mMiddleX = (mTouchX + mCornerX) / 2; - mMiddleY = (mTouchY + mCornerY) / 2; - mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) - * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); - mBezierControl1.y = mCornerY; - mBezierControl2.x = mCornerX; - - float f4 = mCornerY-mMiddleY; - if (f4 == 0) { - mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) - * (mCornerX - mMiddleX) / 0.1f; - - }else { - mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) - * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); - } - mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) - / 2; - mBezierStart1.y = mCornerY; - - // 当mBezierStart1.x < 0或者mBezierStart1.x > 480时 - // 如果继续翻页,会出现BUG故在此限制 - if (mTouchX > 0 && mTouchX < mScreenWidth) { - if (mBezierStart1.x < 0 || mBezierStart1.x > mScreenWidth) { - if (mBezierStart1.x < 0) - mBezierStart1.x = mScreenWidth - mBezierStart1.x; - - float f1 = Math.abs(mCornerX - mTouchX); - float f2 = mScreenWidth * f1 / mBezierStart1.x; - mTouchX = Math.abs(mCornerX - f2); - - float f3 = Math.abs(mCornerX - mTouchX) - * Math.abs(mCornerY - mTouchY) / f1; - mTouchY = Math.abs(mCornerY - f3); - - mMiddleX = (mTouchX + mCornerX) / 2; - mMiddleY = (mTouchY + mCornerY) / 2; - - mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) - * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); - mBezierControl1.y = mCornerY; - - mBezierControl2.x = mCornerX; - - float f5 = mCornerY-mMiddleY; - if (f5 == 0) { - mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) - * (mCornerX - mMiddleX) / 0.1f; - }else { - mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) - * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); - } - - mBezierStart1.x = mBezierControl1.x - - (mCornerX - mBezierControl1.x) / 2; - } - } - mBezierStart2.x = mCornerX; - mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y) - / 2; - - mTouchToCornerDis = (float) Math.hypot((mTouchX - mCornerX), - (mTouchY - mCornerY)); - - mBezierEnd1 = getCross(new PointF(mTouchX,mTouchY), mBezierControl1, mBezierStart1, - mBezierStart2); - mBezierEnd2 = getCross(new PointF(mTouchX,mTouchY), mBezierControl2, mBezierStart1, - mBezierStart2); - - 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; - } - - /** - * 求解直线P1P2和直线P3P4的交点坐标 - * - * @param P1 - * @param P2 - * @param P3 - * @param P4 - * @return - */ - 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; - } -} \ No newline at end of file diff --git a/app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.kt b/app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.kt new file mode 100644 index 0000000..9d9fb3b --- /dev/null +++ b/app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.kt @@ -0,0 +1,662 @@ +package com.novel.read.widget.page.anim + +import android.graphics.* +import android.graphics.drawable.GradientDrawable +import android.os.Build +import android.view.View +import com.novel.read.widget.page.PageAnimation + +/** + * Created by zlj + * 仿真动画 + */ + +class SimulationPageAnim(w: Int, h: Int, view: View, listener: PageAnimation.OnPageChangeListener) : + HorizonPageAnim(w, h, view, listener) { + + private var mCornerX = 1 // 拖拽点对应的页脚 + private var mCornerY = 1 + private val mPath0: Path = Path() + private val mPath1: Path = Path() + + private val mBezierStart1 = PointF() // 贝塞尔曲线起始点 + private val mBezierControl1 = PointF() // 贝塞尔曲线控制点 + private val mBeziervertex1 = PointF() // 贝塞尔曲线顶点 + private var mBezierEnd1 = PointF() // 贝塞尔曲线结束点 + + private val mBezierStart2 = PointF() // 另一条贝塞尔曲线 + private val mBezierControl2 = PointF() + private val mBeziervertex2 = PointF() + private var mBezierEnd2 = PointF() + + private var mMiddleX: Float = 0.toFloat() + private var mMiddleY: Float = 0.toFloat() + private var mDegrees: Float = 0.toFloat() + private var mTouchToCornerDis: Float = 0.toFloat() + private val mColorMatrixFilter: ColorMatrixColorFilter + private val mMatrix: Matrix + private val mMatrixArray = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 1.0f) + + private var mIsRTandLB: Boolean = false // 是否属于右上左下 + private val mMaxLength: Float = + Math.hypot(mScreenWidth.toDouble(), mScreenHeight.toDouble()).toFloat() + private var mBackShadowColors: IntArray? = null// 背面颜色组 + private var mFrontShadowColors: IntArray? = null// 前面颜色组 + private var mBackShadowDrawableLR: GradientDrawable? = null // 有阴影的GradientDrawable + private var mBackShadowDrawableRL: GradientDrawable? = null + private var mFolderShadowDrawableLR: GradientDrawable? = null + private var mFolderShadowDrawableRL: GradientDrawable? = null + + private var mFrontShadowDrawableHBT: GradientDrawable? = null + private var mFrontShadowDrawableHTB: GradientDrawable? = null + private var mFrontShadowDrawableVLR: GradientDrawable? = null + private var mFrontShadowDrawableVRL: GradientDrawable? = null + + private val mPaint: Paint = Paint() + + init { + + mPaint.style = Paint.Style.FILL + + createDrawable() + + val cm = ColorMatrix()//设置颜色数组 + val array = floatArrayOf(1f, 0f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 0f, 1f, 0f) + cm.set(array) + mColorMatrixFilter = ColorMatrixColorFilter(cm) + mMatrix = Matrix() + + mTouchX = 0.01f // 不让x,y为0,否则在点计算时会有问题 + mTouchY = 0.01f + } + + override fun drawMove(canvas: Canvas) { + when (mDirection) { + PageAnimation.Direction.NEXT -> { + calcPoints() + drawCurrentPageArea(canvas, mCurBitmap, mPath0) + drawNextPageAreaAndShadow(canvas, mNextBitmap) + drawCurrentPageShadow(canvas) + drawCurrentBackArea(canvas, mCurBitmap) + } + else -> { + calcPoints() + drawCurrentPageArea(canvas, mNextBitmap, mPath0) + drawNextPageAreaAndShadow(canvas, mCurBitmap) + drawCurrentPageShadow(canvas) + drawCurrentBackArea(canvas, mNextBitmap) + } + } + } + + override fun drawStatic(canvas: Canvas) { + if (isCancel) { + mNextBitmap = mCurBitmap.copy(Bitmap.Config.RGB_565, true) + canvas.drawBitmap(mCurBitmap, 0f, 0f, null) + } else { + canvas.drawBitmap(mNextBitmap, 0f, 0f, null) + } + } + + override fun startAnim() { + super.startAnim() + var dx: Int + val dy: Int + // dx 水平方向滑动的距离,负值会使滚动向左滚动 + // dy 垂直方向滑动的距离,负值会使滚动向上滚动 + if (isCancel) { + + if (mCornerX > 0 && mDirection == PageAnimation.Direction.NEXT) { + dx = (mScreenWidth - mTouchX).toInt() + } else { + dx = -mTouchX.toInt() + } + + if (mDirection != PageAnimation.Direction.NEXT) { + dx = (-(mScreenWidth + mTouchX)).toInt() + } + + if (mCornerY > 0) { + dy = (mScreenHeight - mTouchY).toInt() + } else { + dy = -mTouchY.toInt() // 防止mTouchY最终变为0 + } + } else { + if (mCornerX > 0 && mDirection == PageAnimation.Direction.NEXT) { + dx = -(mScreenWidth + mTouchX).toInt() + } else { + dx = (mScreenWidth - mTouchX + mScreenWidth).toInt() + } + if (mCornerY > 0) { + dy = (mScreenHeight - mTouchY).toInt() + } else { + dy = (1 - mTouchY).toInt() // 防止mTouchY最终变为0 + } + } + mScroller.startScroll(mTouchX.toInt(), mTouchY.toInt(), dx, dy, 400) + } + + override fun setDirection(direction: PageAnimation.Direction) { + super.setDirection(direction) + + when (direction) { + PageAnimation.Direction.PRE -> + //上一页滑动不出现对角 + if (mStartX > mScreenWidth / 2) { + calcCornerXY(mStartX, mScreenHeight.toFloat()) + } else { + calcCornerXY(mScreenWidth - mStartX, mScreenHeight.toFloat()) + } + PageAnimation.Direction.NEXT -> if (mScreenWidth / 2 > mStartX) { + calcCornerXY(mScreenWidth - mStartX, mStartY) + } + } + } + + override fun setStartPoint(x: Float, y: Float) { + super.setStartPoint(x, y) + calcCornerXY(x, y) + } + + override fun setTouchPoint(x: Float, y: Float) { + super.setTouchPoint(x, y) + //触摸y中间位置吧y变成屏幕高度 + if (mStartY > mScreenHeight / 3 && mStartY < mScreenHeight * 2 / 3 || mDirection == PageAnimation.Direction.PRE) { + mTouchY = mScreenHeight.toFloat() + } + + if (mStartY > mScreenHeight / 3 && mStartY < mScreenHeight / 2 && mDirection == PageAnimation.Direction.NEXT) { + mTouchY = 1f + } + } + + /** + * 创建阴影的GradientDrawable + */ + private fun createDrawable() { + val color = intArrayOf(0x333333, -0x4fcccccd) + mFolderShadowDrawableRL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, color + ) + mFolderShadowDrawableRL!!.gradientType = GradientDrawable.LINEAR_GRADIENT + + mFolderShadowDrawableLR = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, color + ) + mFolderShadowDrawableLR!!.gradientType = GradientDrawable.LINEAR_GRADIENT + + mBackShadowColors = intArrayOf(-0xeeeeef, 0x111111) + mBackShadowDrawableRL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors + ) + mBackShadowDrawableRL!!.gradientType = GradientDrawable.LINEAR_GRADIENT + + mBackShadowDrawableLR = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors + ) + mBackShadowDrawableLR!!.gradientType = GradientDrawable.LINEAR_GRADIENT + + mFrontShadowColors = intArrayOf(-0x7feeeeef, 0x111111) + mFrontShadowDrawableVLR = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors + ) + mFrontShadowDrawableVLR!!.gradientType = GradientDrawable.LINEAR_GRADIENT + mFrontShadowDrawableVRL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors + ) + mFrontShadowDrawableVRL!!.gradientType = GradientDrawable.LINEAR_GRADIENT + + mFrontShadowDrawableHTB = GradientDrawable( + GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors + ) + mFrontShadowDrawableHTB!!.gradientType = GradientDrawable.LINEAR_GRADIENT + + mFrontShadowDrawableHBT = GradientDrawable( + GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors + ) + mFrontShadowDrawableHBT!!.gradientType = GradientDrawable.LINEAR_GRADIENT + } + + /** + * 是否能够拖动过去 + * + * @return + */ + fun canDragOver(): Boolean { + return if (mTouchToCornerDis > mScreenWidth / 10) true else false + } + + fun right(): Boolean { + return if (mCornerX > -4) false else true + } + + /** + * 绘制翻起页背面 + * + * @param canvas + * @param bitmap + */ + private fun drawCurrentBackArea(canvas: Canvas, bitmap: Bitmap) { + val i = (mBezierStart1.x + mBezierControl1.x).toInt() / 2 + val f1 = Math.abs(i - mBezierControl1.x) + val i1 = (mBezierStart2.y + mBezierControl2.y).toInt() / 2 + val f2 = Math.abs(i1 - mBezierControl2.y) + val 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(mTouchX, mTouchY) + mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y) + mPath1.close() + val mFolderShadowDrawable: GradientDrawable? + val left: Int + val right: Int + if (mIsRTandLB) { + left = (mBezierStart1.x - 1).toInt() + right = (mBezierStart1.x + f3 + 1f).toInt() + mFolderShadowDrawable = mFolderShadowDrawableLR + } else { + left = (mBezierStart1.x - f3 - 1f).toInt() + right = (mBezierStart1.x + 1).toInt() + mFolderShadowDrawable = mFolderShadowDrawableRL + } + canvas.save() + try { + canvas.clipPath(mPath0) + if (Build.VERSION.SDK_INT >= 28) { + canvas.clipPath(mPath1) + } else { + canvas.clipPath(mPath1, Region.Op.INTERSECT) + } + } catch (e: Exception) { + } + + mPaint.colorFilter = mColorMatrixFilter + //对Bitmap进行取色 + val color = bitmap.getPixel(1, 1) + //获取对应的三色 + val red = color and 0xff0000 shr 16 + val green = color and 0x00ff00 shr 8 + val blue = color and 0x0000ff + //转换成含有透明度的颜色 + val tempColor = Color.argb(200, red, green, blue) + + + val dis = Math.hypot( + (mCornerX - mBezierControl1.x).toDouble(), + (mBezierControl2.y - mCornerY).toDouble() + ).toFloat() + val f8 = (mCornerX - mBezierControl1.x) / dis + val f9 = (mBezierControl2.y - mCornerY) / dis + mMatrixArray[0] = 1 - 2f * f9 * f9 + mMatrixArray[1] = 2f * f8 * f9 + mMatrixArray[3] = mMatrixArray[1] + mMatrixArray[4] = 1 - 2f * 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.drawColor(tempColor) + + mPaint.colorFilter = null + + canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y) + mFolderShadowDrawable!!.setBounds( + left, mBezierStart1.y.toInt(), right, + (mBezierStart1.y + mMaxLength).toInt() + ) + mFolderShadowDrawable.draw(canvas) + canvas.restore() + } + + /** + * 绘制翻起页的阴影 + * + * @param canvas + */ + fun drawCurrentPageShadow(canvas: Canvas) { + val degree: Double + if (mIsRTandLB) { + degree = Math.PI / 4 - Math.atan2( + (mBezierControl1.y - mTouchY).toDouble(), + (mTouchX - mBezierControl1.x).toDouble() + ) + } else { + degree = Math.PI / 4 - Math.atan2( + (mTouchY - mBezierControl1.y).toDouble(), + (mTouchX - mBezierControl1.x).toDouble() + ) + } + // 翻起页阴影顶点与touch点的距离 + val d1 = 25.toFloat().toDouble() * 1.414 * Math.cos(degree) + val d2 = 25.toFloat().toDouble() * 1.414 * Math.sin(degree) + val x = (mTouchX + d1).toFloat() + val y: Float + if (mIsRTandLB) { + y = (mTouchY + d2).toFloat() + } else { + y = (mTouchY - d2).toFloat() + } + mPath1.reset() + mPath1.moveTo(x, y) + mPath1.lineTo(mTouchX, mTouchY) + mPath1.lineTo(mBezierControl1.x, mBezierControl1.y) + mPath1.lineTo(mBezierStart1.x, mBezierStart1.y) + mPath1.close() + var rotateDegrees: Float + canvas.save() + try { + + if (Build.VERSION.SDK_INT >= 28) { + canvas.clipOutPath(mPath0) + canvas.clipPath(mPath1) + } else { + canvas.clipPath(mPath0, Region.Op.XOR) + canvas.clipPath(mPath1, Region.Op.INTERSECT) + + } + + } catch (e: Exception) { + // TODO: handle exception + } + + var leftx: Int + var rightx: Int + var mCurrentPageShadow: GradientDrawable? + if (mIsRTandLB) { + leftx = mBezierControl1.x.toInt() + rightx = mBezierControl1.x.toInt() + 25 + mCurrentPageShadow = mFrontShadowDrawableVLR + } else { + leftx = (mBezierControl1.x - 25).toInt() + rightx = mBezierControl1.x.toInt() + 1 + mCurrentPageShadow = mFrontShadowDrawableVRL + } + + rotateDegrees = Math.toDegrees( + Math.atan2( + (mTouchX - mBezierControl1.x).toDouble(), + (mBezierControl1.y - mTouchY).toDouble() + ) + ).toFloat() + canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y) + mCurrentPageShadow!!.setBounds( + leftx, + (mBezierControl1.y - mMaxLength).toInt(), rightx, + mBezierControl1.y.toInt() + ) + mCurrentPageShadow.draw(canvas) + canvas.restore() + + mPath1.reset() + mPath1.moveTo(x, y) + mPath1.lineTo(mTouchX, mTouchY) + mPath1.lineTo(mBezierControl2.x, mBezierControl2.y) + mPath1.lineTo(mBezierStart2.x, mBezierStart2.y) + mPath1.close() + canvas.save() + try { + if (Build.VERSION.SDK_INT >= 28) { + canvas.clipOutPath(mPath0) + canvas.clipPath(mPath1) + } else { + canvas.clipPath(mPath0, Region.Op.XOR) + canvas.clipPath(mPath1, Region.Op.INTERSECT) + } + } catch (e: Exception) { + } + + if (mIsRTandLB) { + leftx = mBezierControl2.y.toInt() + rightx = (mBezierControl2.y + 25).toInt() + mCurrentPageShadow = mFrontShadowDrawableHTB + } else { + leftx = (mBezierControl2.y - 25).toInt() + rightx = (mBezierControl2.y + 1).toInt() + mCurrentPageShadow = mFrontShadowDrawableHBT + } + rotateDegrees = Math.toDegrees( + Math.atan2( + (mBezierControl2.y - mTouchY).toDouble(), + (mBezierControl2.x - mTouchX).toDouble() + ) + ).toFloat() + canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y) + val temp: Float + if (mBezierControl2.y < 0) + temp = mBezierControl2.y - mScreenHeight + else + temp = mBezierControl2.y + + val hmg = Math.hypot(mBezierControl2.x.toDouble(), temp.toDouble()).toInt() + if (hmg > mMaxLength) + mCurrentPageShadow!! + .setBounds( + (mBezierControl2.x - 25).toInt() - hmg, leftx, + (mBezierControl2.x + mMaxLength).toInt() - hmg, + rightx + ) + else + mCurrentPageShadow!!.setBounds( + (mBezierControl2.x - mMaxLength).toInt(), leftx, + mBezierControl2.x.toInt(), rightx + ) + + mCurrentPageShadow.draw(canvas) + canvas.restore() + } + + private fun 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.toFloat(), mCornerY.toFloat()) + mPath1.close() + + mDegrees = Math.toDegrees( + Math.atan2( + (mBezierControl1.x - mCornerX).toDouble(), + (mBezierControl2.y - mCornerY).toDouble() + ) + ).toFloat() + val leftx: Int + val rightx: Int + val mBackShadowDrawable: GradientDrawable? + if (mIsRTandLB) { //左下及右上 + leftx = mBezierStart1.x.toInt() + rightx = (mBezierStart1.x + mTouchToCornerDis / 4).toInt() + mBackShadowDrawable = mBackShadowDrawableLR + } else { + leftx = (mBezierStart1.x - mTouchToCornerDis / 4).toInt() + rightx = mBezierStart1.x.toInt() + mBackShadowDrawable = mBackShadowDrawableRL + } + canvas.save() + try { + + if (Build.VERSION.SDK_INT >= 28) { + canvas.clipPath(mPath0) + canvas.clipPath(mPath1) + } else { + canvas.clipPath(mPath0) + canvas.clipPath(mPath1, Region.Op.INTERSECT) + } + } catch (e: Exception) { + } + + + canvas.drawBitmap(bitmap, 0f, 0f, null) + canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y) + mBackShadowDrawable!!.setBounds( + leftx, mBezierStart1.y.toInt(), rightx, + (mMaxLength + mBezierStart1.y).toInt() + )//左上及右下角的xy坐标值,构成一个矩形 + mBackShadowDrawable.draw(canvas) + canvas.restore() + } + + private fun 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(mTouchX, mTouchY) + mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y) + mPath0.quadTo( + mBezierControl2.x, mBezierControl2.y, mBezierStart2.x, + mBezierStart2.y + ) + mPath0.lineTo(mCornerX.toFloat(), mCornerY.toFloat()) + mPath0.close() + + canvas.save() + // if(Build.VERSION.SDK_INT >= 28){ + // canvas.clipOutPath(path); + // }else { + // canvas.clipPath(path, Region.Op.XOR); + // } + canvas.drawBitmap(bitmap, 0f, 0f, null) + try { + canvas.restore() + } catch (e: Exception) { + + } + + } + + /** + * 计算拖拽点对应的拖拽脚 + * + * @param x + * @param y + */ + fun calcCornerXY(x: Float, y: Float) { + if (x <= mScreenWidth / 2) { + mCornerX = 0 + } else { + mCornerX = mScreenWidth + } + if (y <= mScreenHeight / 2) { + mCornerY = 0 + } else { + mCornerY = mScreenHeight + } + + if (mCornerX == 0 && mCornerY == mScreenHeight || mCornerX == mScreenWidth && mCornerY == 0) { + mIsRTandLB = true + } else { + mIsRTandLB = false + } + + } + + private fun calcPoints() { + mMiddleX = (mTouchX + mCornerX) / 2 + mMiddleY = (mTouchY + mCornerY) / 2 + mBezierControl1.x = + mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX) + mBezierControl1.y = mCornerY.toFloat() + mBezierControl2.x = mCornerX.toFloat() + + val f4 = mCornerY - mMiddleY + if (f4 == 0f) { + mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f + + } else { + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) + } + mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2 + mBezierStart1.y = mCornerY.toFloat() + + // 当mBezierStart1.x < 0或者mBezierStart1.x > 480时 + // 如果继续翻页,会出现BUG故在此限制 + if (mTouchX > 0 && mTouchX < mScreenWidth) { + if (mBezierStart1.x < 0 || mBezierStart1.x > mScreenWidth) { + if (mBezierStart1.x < 0) + mBezierStart1.x = mScreenWidth - mBezierStart1.x + + val f1 = Math.abs(mCornerX - mTouchX) + val f2 = mScreenWidth * f1 / mBezierStart1.x + mTouchX = Math.abs(mCornerX - f2) + + val f3 = Math.abs(mCornerX - mTouchX) * Math.abs(mCornerY - mTouchY) / f1 + mTouchY = Math.abs(mCornerY - f3) + + mMiddleX = (mTouchX + mCornerX) / 2 + mMiddleY = (mTouchY + mCornerY) / 2 + + mBezierControl1.x = + mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX) + mBezierControl1.y = mCornerY.toFloat() + + mBezierControl2.x = mCornerX.toFloat() + + val f5 = mCornerY - mMiddleY + if (f5 == 0f) { + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f + } else { + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) + } + + mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2 + } + } + mBezierStart2.x = mCornerX.toFloat() + mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y) / 2 + + mTouchToCornerDis = Math.hypot( + (mTouchX - mCornerX).toDouble(), + (mTouchY - mCornerY).toDouble() + ).toFloat() + + mBezierEnd1 = getCross( + PointF(mTouchX, mTouchY), mBezierControl1, mBezierStart1, + mBezierStart2 + ) + mBezierEnd2 = getCross( + PointF(mTouchX, mTouchY), mBezierControl2, mBezierStart1, + mBezierStart2 + ) + + 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 + } + + /** + * 求解直线P1P2和直线P3P4的交点坐标 + * + * @param P1 + * @param P2 + * @param P3 + * @param P4 + * @return + */ + fun getCross(P1: PointF, P2: PointF, P3: PointF, P4: PointF): PointF { + val CrossP = PointF() + // 二元函数通式: y=ax+b + val a1 = (P2.y - P1.y) / (P2.x - P1.x) + val b1 = (P1.x * P2.y - P2.x * P1.y) / (P1.x - P2.x) + + val a2 = (P4.y - P3.y) / (P4.x - P3.x) + val 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 + } + + companion object { + private val TAG = "SimulationPageAnim" + } +} \ No newline at end of file