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