最近重看了一遍封神演义,感受QQ阅读那个翻书的效果挺好的,准备作一个。上周五下午用了两个小时只写了一部分功能,之后有时间再完善git
先看效果图github
其中a点就是手指的位置,b点就是控件右下角,cd为ab的垂直平分线,e为交点,gh为ae的垂直平分线,f为交点,i为ac与gh的交点,j为ad与gh的交点,其中icg为贝塞尔曲线,c为控制点,jdh为贝塞尔曲线,d为控制点,构建一个aigbh的path,经过canvas裁剪这个pathcanvas
private fun calPoints(x: Float,y:Float) {
pointA.x = x
pointA.y = y
calPointB()
pointE.x = (pointA.x + pointB.x) / 2
pointE.y = (pointA.y + pointB.y) / 2
pointK.x = pointE.x
pointK.y = pointB.y
pointC.x = pointK.x - (pointK.y - pointE.y) * (pointK.y - pointE.y) / (pointB.x - pointK.x)
pointC.y = pointB.y
pointG.x = pointC.x - (pointB.x - pointC.x) / 2
pointG.y = pointB.y
pointL.x = pointB.x
pointL.y = pointE.y
pointD.x = pointB.x
pointD.y = pointE.y - (pointL.x - pointE.x) * (pointL.x - pointE.x) / (pointB.y - pointL.y)
pointF.x = (pointA.x + pointE.x) / 2
pointF.y = (pointA.y + pointE.y) / 2
pointH.x = pointB.x
pointH.y = pointD.y - (pointB.y - pointD.y) / 2
pointI = getIntercetPoint(pointA, pointC, pointH, pointG)
pointJ = getIntercetPoint(pointA, pointD, pointH, pointG)
}
private fun calPointB() {
when {
this.touchPos == TOUCH_END -> {
pointB.x = width.toFloat()
pointB.y = height.toFloat()
}
this.touchPos == TOUCH_TOP -> {
pointB.x = width.toFloat()
pointB.y = 0f
}
else -> {
pointB.x = pointA.x
pointB.y = height.toFloat()
}
}
}
private fun getIntercetPoint(point1: Point, point2: Point, point3: Point, point4: Point): Point {
var x1 = point1.x
var y1 = point1.y
var x2 = point2.x
var y2 = point2.y
var x3 = point3.x
var y3 = point3.y
var x4 = point4.x
var y4 = point4.y
var pointX =
((x1 - x2) * (x3 * y4 - x4 * y3) - (x3 - x4) * (x1 * y2 - x2 * y1)) / ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4))
var pointY =
((y1 - y2) * (x3 * y4 - x4 * y3) - (x1 * y2 - x2 * y1) * (y3 - y4)) / ((y1 - y2) * (x3 - x4) - (x1 - x2) * (y3 - y4))
return Point(pointX, pointY)
}
复制代码
每一个点怎么算代码已经很清楚了,我也就再也不赘述了。bash
override fun draw(canvas: Canvas?) {
canvas?.let {
it.save()
calPath()
it.clipPath(path, Region.Op.XOR)
super.draw(it)
it.restore()
}
}
private fun calPath() {
path.reset()
path.moveTo(pointA.x, pointA.y)
path.lineTo(pointI.x, pointI.y)
path.quadTo(pointC.x, pointC.y, pointG.x, pointG.y)
path.lineTo(pointB.x, pointB.y)
path.lineTo(pointH.x, pointH.y)
path.quadTo(pointD.x, pointD.y, pointJ.x, pointJ.y)
path.lineTo(pointA.x, pointA.y)
}
复制代码
复写draw方法,经过calPath构建ajgbhja这样的一个path,裁减掉这部分后进行绘制。ide
当g点x的坐标为0是,就中止移动了post
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
lastTouchX=event.x
lastTouchY=event.y
when {
event.y < height / 3 -> this.touchPos = TOUCH_TOP
event.y > height - height / 3 -> this.touchPos = TOUCH_END
else -> this.touchPos = TOUCH_MID
}
}
MotionEvent.ACTION_MOVE -> {
calPoints(event.x,event.y)
if(pointG.x<=0)
{
calPoints(lastTouchX,lastTouchY)
}
else{
lastTouchX=event.x
lastTouchY=event.y
}
postInvalidate()
}
MotionEvent.ACTION_UP -> {
}
}
return true
}
复制代码
最近状态不好,写代码老是写写停停,不能静下心来,因此这个控件有不少没有作完,之后有时间再弄吧。附github地址ui
关注个人公众号this