转换部分java代码

old
zlj 5 years ago
parent 78adf7d216
commit 1c0f80809b
  1. 6
      app/src/main/java/com/novel/read/widget/page/anim/CoverPageAnim.kt
  2. 232
      app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.java
  3. 223
      app/src/main/java/com/novel/read/widget/page/anim/HorizonPageAnim.kt
  4. 655
      app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.java
  5. 662
      app/src/main/java/com/novel/read/widget/page/anim/SimulationPageAnim.kt

@ -15,13 +15,11 @@ import com.novel.read.widget.page.PageAnimation
class CoverPageAnim(w: Int, h: Int, view: View, listener: PageAnimation.OnPageChangeListener) : class CoverPageAnim(w: Int, h: Int, view: View, listener: PageAnimation.OnPageChangeListener) :
HorizonPageAnim(w, h, view, listener) { HorizonPageAnim(w, h, view, listener) {
private val mSrcRect: Rect private val mSrcRect: Rect = Rect(0, 0, mViewWidth, mViewHeight)
private val mDestRect: Rect private val mDestRect: Rect = Rect(0, 0, mViewWidth, mViewHeight)
private val mBackShadowDrawableLR: GradientDrawable private val mBackShadowDrawableLR: GradientDrawable
init { init {
mSrcRect = Rect(0, 0, mViewWidth, mViewHeight)
mDestRect = Rect(0, 0, mViewWidth, mViewHeight)
val mBackShadowColors = intArrayOf(0x66000000, 0x00000000) val mBackShadowColors = intArrayOf(0x66000000, 0x00000000)
mBackShadowDrawableLR = GradientDrawable( mBackShadowDrawableLR = GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors

@ -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…
Cancel
Save