if (!mRegionShortSize.contains((int)mTouchX, (int)mTouchY)) {
/*
如果不在则通过x坐标强行重算y坐标
通过圆的标准方程: (x-a)^2+(y-b)^2=r^2 (a,b)为圆心 r为半径 x,y为圆弧上的一点
y - b = Math.sqrt(r^2 - (x-a)^2) => y = Math.sqrt(r^2 - (x-a)^2) + b
或
-(y - b) = Math.sqrt(r^2 - (x-a)^2) => y = -1 * Math.sqrt(r^2 - (x-a)^2) + b
*/
// mTouchY = (float) (Math.sqrt((Math.pow(mW, 2) - Math.pow(mTouchX, 2))) + mH); // 明显值大于mH,不对
mTouchY = (float) (-1 * Math.sqrt((Math.pow(mW, 2) - Math.pow(mTouchX, 2))) + mH);
}这样算出来的mTouchY即是圆的轨迹上的对应横坐标的纵坐标值package com.stone.turnpage.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* author : stone
* email : aa86799@163.com
* time : 16/9/20 11 18
*
* 折线翻页
*/
public class FoldTurnPageView extends View {
private float mTouchX, mTouchY;
private Path mPath;
private Paint mPaint;
private int mW, mH;
private Region mRegionShortSize;
public FoldTurnPageView(Context context) {
this(context, null);
}
public FoldTurnPageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FoldTurnPageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(10);
mRegionShortSize = new Region();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public FoldTurnPageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mTouchX = event.getX();
mTouchY = event.getY();
System.out.println(mTouchY);
if (!mRegionShortSize.contains((int)mTouchX, (int)mTouchY)) {
/*
如果不在则通过x坐标强行重算y坐标
通过圆的标准方程: (x-a)^2+(y-b)^2=r^2 (a,b)为圆心 r为半径 x,y为圆弧上的一点
y - b = Math.sqrt(r^2 - (x-a)^2) => y = Math.sqrt(r^2 - (x-a)^2) + b
或
-(y - b) = Math.sqrt(r^2 - (x-a)^2) => y = -1 * Math.sqrt(r^2 - (x-a)^2) + b
*/
// mTouchY = (float) (Math.sqrt((Math.pow(mW, 2) - Math.pow(mTouchX, 2))) + mH);
mTouchY = (float) (-1 * Math.sqrt((Math.pow(mW, 2) - Math.pow(mTouchX, 2))) + mH);
}
invalidate();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mW = getMeasuredWidth();
mH = getMeasuredHeight();
computeShortSizeRegion();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
float k = mW - mTouchX;
float l = mH - mTouchY;
float c = (float) (Math.pow(k, 2) + Math.pow(l, 2));
float x = c / (2 * k);
float y = c / (2 * l);
mPath.moveTo(mTouchX, mTouchY); //O点
mPath.lineTo(mW - x, mH); //A点
mPath.lineTo(mW, mH - y); //B点
mPath.close();
mPaint.setColor(Color.RED);
canvas.drawPath(mPath, mPaint);
mPaint.setColor(Color.GREEN);
mPath.reset();
mPath.addCircle(0, mH, mW, Path.Direction.CCW);
canvas.drawPath(mPath, mPaint);
}
/**
* 计算短边的有效区域
*/
private void computeShortSizeRegion() {
// 短边圆形路径对象
Path pathShortSize = new Path();
// 添加圆形到Path
pathShortSize.addCircle(0, mH, mW, Path.Direction.CCW);
RectF bounds = new RectF();
pathShortSize.computeBounds(bounds, true);
//region.setPath 参数Region clip, 用于裁剪
mRegionShortSize.setPath(pathShortSize, new Region((int)bounds.left, (int)bounds.top,
(int)bounds.right, (int)bounds.bottom));
}
}
package com.stone.turnpage.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.IntDef;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* author : stone
* email : aa86799@163.com
* time : 16/9/20 11 18
* <p>
* 折线翻页
*/
public class FoldTurnPageView extends View {
private float mTouchX, mTouchY;
private float mTouchUpX, mTouchUpY;//touch-up 时点的坐标
private Path mPath;
private Paint mPaint;
private int mW, mH;
private Region mRegionShortSize;
private int mBuffArea = 20; //底部缓冲区
private float mAutoAreaRight, mAutoAreaBottom, mAutoAreaLeft;
private boolean mIsSlide; //是否自动滑动
private static final int LEFT_BOTTOM = 1; //左下
private static final int RIGHT_BOTTOM = 2; //右下
@IntDef({LEFT_BOTTOM, RIGHT_BOTTOM})
@Retention(RetentionPolicy.SOURCE)
private @interface SlideDirection {}
@SlideDirection
private int mSlide;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (!mIsSlide) {
return;
}
if (mSlide == RIGHT_BOTTOM && mTouchX < mW) {//向下滑动
mTouchX += 10;
/*
根据直线方程公式:(y-y1)/(y2-y1)=(x-x1)/(x2-x1)
y=y1+(x-x1)*(y2-y1)/(x2-x1)
mTouchUpX <==> x1 mTouchUpY <==> y1
mW <==> x2 mH <==> y2
不断变化的点 mTouchX <==> x mTouchY <==> y
*/
mTouchY = mTouchUpY + (mTouchX - mTouchUpX) * (mH - mTouchUpY) / (mW - mTouchUpX);
invalidate();
sendMessageDelayed(obtainMessage(0), 25);
} else if (mSlide == LEFT_BOTTOM && mTouchX > -mW) {//向左滑动
mTouchX -= 40;
mTouchY = mTouchUpY + (mTouchX - mTouchUpX) * (mH - mTouchUpY) / (-mW - mTouchUpX);
invalidate();
sendMessageDelayed(obtainMessage(0), 25);
} else {
slideStop();
}
}
};
public FoldTurnPageView(Context context) {
this(context, null);
}
public FoldTurnPageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FoldTurnPageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(10);
mRegionShortSize = new Region();
// setLayerType(LAYER_TYPE_SOFTWARE, null); //关闭硬件加速 api11以上 在manifest中关闭
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public FoldTurnPageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
mTouchX = x;
mTouchY = y;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mHandler.removeMessages(0);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
invalidate();
break;
case MotionEvent.ACTION_UP:
if (x > mAutoAreaRight && y > mAutoAreaBottom) {
mSlide = RIGHT_BOTTOM;
startSlide(x, y);
} else if (x < mAutoAreaLeft) {
mSlide = LEFT_BOTTOM;
startSlide(x, y);
}
break;
}
return true;
}
private void startSlide(float x, float y ) {
mIsSlide = true;
mTouchUpX = x;
mTouchUpY = y;
mHandler.sendEmptyMessage(0);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mW = getMeasuredWidth();
mH = getMeasuredHeight();
computeShortSizeRegion();
mAutoAreaRight = mW / 4 * 3;
mAutoAreaBottom = mH / 4 * 3;
mAutoAreaLeft = mW / 8;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// canvas.clipRegion(mRegionShortSize);
canvas.drawColor(Color.parseColor("#d8ccaa00"));
if (!mRegionShortSize.contains((int) mTouchX, (int) mTouchY)) {
/*
如果不在则通过x坐标强行重算y坐标
通过圆的标准方程: (x-a)^2+(y-b)^2=r^2 (a,b)为圆心 r为半径 x,y为圆弧上的一点
y - b = Math.sqrt(r^2 - (x-a)^2) => y = Math.sqrt(r^2 - (x-a)^2) + b
或
-(y - b) = Math.sqrt(r^2 - (x-a)^2) => y = -1 * Math.sqrt(r^2 - (x-a)^2) + b
*/
// mTouchY = (float) (Math.sqrt((Math.pow(mW, 2) - Math.pow(mTouchX, 2))) + mH); // 使用这个明显值偏大 比mH大
mTouchY = (float) (-1 * Math.sqrt((Math.pow(mW, 2) - Math.pow(mTouchX, 2))) + mH);
}
/*
缓冲区域判断
当B点不在PB线上,而在屏幕上方之外,这时mTouchX, 偏左
此时 mTouchY 越接近mH , 折线出的就不能形成?AOB了 而是一个矩形
*/
float area = mH - mBuffArea;
if (mTouchY >= area && !mIsSlide) {
mTouchY = area;
}
float k = mW - mTouchX;
float l = mH - mTouchY;
float c = (float) (Math.pow(k, 2) + Math.pow(l, 2));
float x = c / (2 * k);
float y = c / (2 * l);
mPath.reset();
mPath.moveTo(mTouchX, mTouchY); //O点
if (y > mH) {//B点超出屏幕上端
//计算,BN边
float bn = y - mH;
//MN=BN/BD*OD
float mn = bn / (y - (mH - mTouchY)) * (mW - mTouchX);
//QN=BN/BP*AP
float qn = bn / y * x;
mPath.lineTo(mW - mn, 0); //M点
mPath.lineTo(mW - qn, 0); //Q点
mPath.lineTo(mW - x, mH); //A点 在底部
} else {
mPath.lineTo(mW, mH - y); //B点 在右部
mPath.lineTo(mW - x, mH); //A点 在底部
}
mPath.close();
mPaint.setColor(Color.RED);
canvas.drawPath(mPath, mPaint);
mPaint.setColor(Color.GREEN);
mPath.reset();
mPath.addCircle(0, mH, mW, Path.Direction.CCW);
canvas.drawPath(mPath, mPaint);
}
/**
* 计算短边的有效区域
*/
private void computeShortSizeRegion() {
// 短边圆形路径对象
Path pathShortSize = new Path();
// 添加圆形到Path
pathShortSize.addCircle(0, mH, mW, Path.Direction.CCW);
RectF bounds = new RectF();
pathShortSize.computeBounds(bounds, true);
//region.setPath 参数Region clip, 用于裁剪
boolean flag = mRegionShortSize.setPath(pathShortSize, new Region((int) bounds.left, (int) bounds.top,
(int) bounds.right, (int) bounds.bottom));
// boolean flag = mRegionShortSize.setPath(pathShortSize, new Region(0, 1920-1080, 500, 1920));
// System.out.println(bounds + ",," + flag);
// System.out.println(mRegionShortSize);
}
/**
* 为isSlide提供对外的停止方法便于必要时释放滑动动画
*/
public void slideStop() {
mIsSlide = false;
}
}
if (y > mH) {//B点超出屏幕上端
//计算,BN边
float bn = y - mH;
//MN=BN/BD*OD
float mn = bn / (y - (mH - mTouchY)) * (mW - mTouchX);
//QN=BN/BP*AP
float qn = bn / y * x;
mPath.lineTo(mW - mn, 0); //M点
mPath.lineTo(mW - qn, 0); //Q点
mPath.lineTo(mW - x, mH); //A点 在底部
/*
生成包含折叠和下一页的路径
OMNPA 五点
*/
mPathFoldAndNext.lineTo(mW - mn, 0); //M
mPathFoldAndNext.lineTo(mW, 0); //N
mPathFoldAndNext.lineTo(mW, mH); //P
mPathFoldAndNext.lineTo(mW - x, mH); //A
} else {
mPath.lineTo(mW, mH - y); //B点 在右部
mPath.lineTo(mW - x, mH); //A点 在底部
/*
生成包含折叠和下一页的路径
OBPA 四点
*/
mPathFoldAndNext.lineTo(mW, mH - y); //B点 在右部
mPathFoldAndNext.lineTo(mW, mH); //P点
mPathFoldAndNext.lineTo(mW - x, mH); //A点 在底部
}原文:http://blog.csdn.net/jjwwmlp456/article/details/52598387