parent
78adf7d216
commit
1c0f80809b
@ -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; |
|
||||||
} |
|
||||||
} |
|
@ -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" |
||||||
|
} |
||||||
|
} |
@ -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; |
|
||||||
} |
|
||||||
} |
|
@ -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" |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue