Android翻书效果-双页模式

在写这个双页模式前,首先先借鉴了一下 http://blog.csdn.net/hmg25/article/details/6306479  这里的翻页原理

然后根据自己的理解实现了一下双页模式,但是在加贝塞尔曲线的时候,效果不是很理象,这里把自己的思路记录一下。

Android翻书效果-双页模式_第1张图片

这里来讲述一下以右下角开始翻页(参见上图)

当我们开始翻动的时候,与X轴有交战P,与Y轴有交战Q

当X轴上的值(Px)小于View的一半的时候,我们需要重新计算这个点所带来的其他值,我们要将P点移动到M

这里已知T点,M点,O点三点坐标   线段MO=MS ,做垂线TB交PO于B,垂线SA交PO于A

求出S点坐标即可

 

已知T、M两点,可以求出TM的长,TB的长,MB的长,

MO = SM,显然 △TMB∽△SMA ,可以求出SA的长,MA的长,可解得S点坐标

 

这里S点 就是我们的Touch点坐标,根据这个新的Touch点我们去重新计算与X轴,Y轴的交点坐标等等

 

 下面给出一个模型

public class TurnPage extends View {
	
	/**
	 * 页角的枚举 
	 */
	public enum Corner {
		LeftTop,
		LeftBottom,
		RightTop,
		RightBottom,
		None
	}
	
	PointF touch = new PointF();		// 触摸点
	PointF corner = new PointF();		// 页角点
	PointF middle = new PointF();		// 触摸与页角的中点
	
	PointF crossX = new PointF();		// 与X轴的焦点
	PointF crossY = new PointF();		// 与Y轴的焦点
	
	Corner footer = Corner.None;		// 表示页脚
	
	Path all = new Path();				// 全部掀起的Path
	Path part = new Path();				// 掀起背面的Path

	public TurnPage(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public TurnPage(Context context) {
		super(context);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawColor(Color.WHITE);
		if(footer == Corner.None) {
			return;
		}
		this.transPath();
		canvas.clipPath(all);
		canvas.drawColor(Color.LTGRAY);
		canvas.clipPath(part, Op.INTERSECT);
		canvas.drawColor(Color.YELLOW);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		touch.x = event.getX();
		touch.y = event.getY();
		if(action == MotionEvent.ACTION_DOWN) {
			this.calCorner();
		}
		if(action == MotionEvent.ACTION_MOVE) {
		}
		if(action == MotionEvent.ACTION_UP) {
		}
		this.calPoints();
		this.judgePoint();
		this.postInvalidate();
		return true;
	}
	
	/**
	 * 计算页角 
	 */
	private void calCorner() {
		if (touch.x < this.getWidth() / 2 && touch.y < this.getHeight() / 2) {
			this.footer = Corner.LeftTop;
			corner.x = 0;
			corner.y = 0;
		} else if (touch.x < this.getWidth() / 2 && this.touch.y >= this.getHeight() / 2) {
			this.footer = Corner.LeftBottom;
			corner.x = 0;
			corner.y = this.getHeight();
		} else if (touch.x >= this.getWidth() / 2 && this.touch.y < this.getHeight() / 2) {
			this.footer = Corner.RightTop;
			corner.x = this.getWidth();
			corner.y = 0;
		} else if (touch.x >= this.getWidth() / 2 && this.touch.y >= this.getHeight() / 2) {
			this.footer = Corner.RightBottom;
			corner.x = this.getWidth();
			corner.y = this.getHeight();
		} else {
			this.footer = Corner.None;
		}
	}
	
	/**
	 * 计算点 
	 */
	private void calPoints() {
		this.middle.x = (touch.x + corner.x) / 2;
		this.middle.y = (touch.y + corner.y) / 2;
		//
		this.crossX.x = middle.x - (corner.y - middle.y) * (corner.y - middle.y) / (corner.x - middle.x);
		this.crossX.y = corner.y;
		this.crossY.x = corner.x;
		this.crossY.y = middle.y - (corner.x - middle.x) * (corner.x - middle.x) / (corner.y - middle.y);
	}
	
	/**
	 * 转换路径的方法 
	 */
	private void transPath() {
		this.all.reset();
		this.all.moveTo(touch.x, touch.y);
		this.all.lineTo(crossX.x, crossX.y);
		this.all.lineTo(corner.x, corner.y);
		this.all.lineTo(crossY.x, crossY.y);
		this.all.close();
		
		this.part.reset();
		this.part.moveTo(touch.x, touch.y);
		this.part.lineTo(crossX.x, crossX.y);
		this.part.lineTo(crossY.x, crossY.y);
		this.part.close();
	}
	
	/**
	 * 判断点是否正确 
	 */
	private void judgePoint() {
		if(touch.x < 0 && touch.x >this.getWidth()) {
			return;
		}
		if(footer == Corner.LeftTop || footer == Corner.LeftBottom) { // 如果在左边
			if(crossX.x >= 0 && crossX.x < this.getWidth() / 2) {
				return;
			}
			if(footer == Corner.LeftTop) {
				this.recalLeftTop();
			} else {
				this.recalLeftBottom();
			}
		}
		if(footer == Corner.RightTop || footer == Corner.RightBottom) {	// 如果在右边
			if(crossX.x >= this.getWidth() / 2 && crossX.x < this.getWidth()) {
				return;
			}
			if(footer == Corner.RightTop) {
				this.recalRightTop();
			} else {
				this.recalRightBottom();
			}
		}
	}
	
	// 重新计算左上
	private void recalLeftTop() {
		PointF mid = new PointF(this.getWidth() / 2, 0);
		float incline = (float) Math.hypot(touch.x - mid.x, touch.y - mid.y);
		float height = Math.abs(mid.y - touch.y);
		float bottom = Math.abs(mid.x - touch.x);
		float x = mid.x * bottom / incline;
		float y = mid.x * height / incline;
		this.touch.y = y;
		if(this.touch.x > mid.x) {
			touch.x = mid.x + x;
		} else {
			touch.x = mid.x - x;
		}
		this.calPoints();
	}
	
	// 重新计算左下
	private void recalLeftBottom() {
		PointF mid = new PointF(this.getWidth() / 2, this.getHeight());
		float incline = (float) Math.hypot(touch.x - mid.x, touch.y - mid.y);
		float height = Math.abs(mid.y - touch.y);
		float bottom = Math.abs(mid.x - touch.x);
		float x = mid.x * bottom / incline;
		float y = mid.x * height / incline;
		this.touch.y = this.getHeight() - y;
		if(this.touch.x > mid.x) {
			touch.x = mid.x + x;
		} else {
			touch.x = mid.x - x;
		}
		this.calPoints();
	}
	
	// 重新计算右上
	private void recalRightTop() {
		PointF mid = new PointF(this.getWidth() / 2, 0);
		float incline = (float) Math.hypot(touch.x - mid.x, touch.y - mid.y);
		float height = Math.abs(touch.y);
		float bottom = Math.abs(touch.x - mid.x);
		float x = mid.x * bottom / incline;
		float y = mid.x * height / incline;
		this.touch.y = y; 
		if(touch.x > mid.x) {
			touch.x = mid.x + x;
		} else {
			touch.x = mid.x - x;
		}
		this.calPoints();
	}
	
	// 重新计算右下
	private void recalRightBottom() {
		PointF mid = new PointF(this.getWidth() / 2, this.getHeight());
		float incline = (float) Math.hypot(touch.x - mid.x, touch.y - mid.y);
		float height = Math.abs(mid.y - touch.y);
		float bottom = Math.abs(touch.x - mid.x);
		float x = mid.x * bottom / incline; 
		float y = mid.x * height / incline;
		this.touch.y = mid.y - y;
		if(touch.x > mid.x) {
			touch.x = mid.x + x;
		} else {
			touch.x = mid.x - x;
		}
		this.calPoints();
	}
}


 

 

 

你可能感兴趣的:(Android翻书效果-双页模式)