核心功能点如下:
计算角度
使用三角函数可以计算出触摸坐标点所对应的角度
/**
* 计算当前的角度
* @param x 触摸坐标点
* @param y 触摸坐标点
*/
private fun updateCurrentAngle(x: Float, y: Float): Double {
val pointX = x - mCenterX
val pointY = y - mCenterY
return if (pointX >= 0 && pointY <= 0) {
//第一象限
"第一象限".print()
atan((pointX / -pointY)).run {
Math.toDegrees(this.toDouble()) + 90f + mOffsetAngle
}.apply {
"角度:$this".print()
}
} else if (pointX <= 0 && pointY >= 0) {
//第三象限
"第三象限".print()
atan(-pointX / pointY).run {
Math.toDegrees(this.toDouble())
}.run {
if (this >= 90f) {
this - 90f
} else {
this + 270
} + mOffsetAngle
}.apply {
"角度:$this".print()
}
} else if (pointX <= 0 && pointY <= 0) {
//第四象限
"第四象限".print()
atan(-pointY / -pointX).run {
Math.toDegrees(this.toDouble()) + mOffsetAngle + 360f
}.apply {
"角度:$this".print()
}
} else {
//第二象限
"第二象限".print()
atan(pointY / pointX).run {
Math.toDegrees(this.toDouble()) + 180 + mOffsetAngle
}.apply {
"角度:$this".print()
}
}
}
计算触摸点射线到圆弧的交叉点
/**
* 依圆心坐标,半径,扇形角度,计算出扇形终射线与圆弧交叉点的xy坐标
*
* @param cirX 圆centerX
* @param cirY 圆centerY
* @param radius 圆半径
* @param cirAngle 当前弧角度
* @return 扇形终射线与圆弧交叉点的xy坐标
*/
private fun calcArcEndPointXY(
cirX: Float, cirY: Float, radius: Float, cirAngle: Float
): PointF {
val posX: Float
val posY: Float
//将角度转换为弧度
var arcAngle = (Math.PI * cirAngle / 180.0).toFloat()
if (cirAngle < 90) {
posX = cirX + cos(arcAngle.toDouble()).toFloat() * radius
posY = cirY + sin(arcAngle.toDouble()).toFloat() * radius
} else if (cirAngle == 90f) {
posX = cirX
posY = cirY + radius
} else if (cirAngle > 90 && cirAngle < 180) {
arcAngle = (Math.PI * (180 - cirAngle) / 180.0).toFloat()
posX = cirX - cos(arcAngle.toDouble()).toFloat() * radius
posY = cirY + sin(arcAngle.toDouble()).toFloat() * radius
} else if (cirAngle == 180f) {
posX = cirX - radius
posY = cirY
} else if (cirAngle > 180 && cirAngle < 270) {
arcAngle = (Math.PI * (cirAngle - 180) / 180.0).toFloat()
posX = cirX - cos(arcAngle.toDouble()).toFloat() * radius
posY = cirY - sin(arcAngle.toDouble()).toFloat() * radius
} else if (cirAngle == 270f) {
posX = cirX
posY = cirY - radius
} else {
arcAngle = (Math.PI * (360 - cirAngle) / 180.0).toFloat()
posX = cirX + cos(arcAngle.toDouble()).toFloat() * radius
posY = cirY - sin(arcAngle.toDouble()).toFloat() * radius
}
return PointF(posX, posY)
}
绘制贴图
mArcPath.apply {
val r = max(measuredWidth, measuredHeight) / 2f
canvas.save()
reset()
moveTo(mCenterX, mCenterY)
val startPoint = calcArcEndPointXY(mCenterX, mCenterY, r, mOffsetAngle)
lineTo(startPoint.x, startPoint.y)
addArc(mRingDrawableRectF, mOffsetAngle - 12f, mSweptAngle.toFloat() + 12f)
lineTo(mCenterX, mCenterY)
close()
}
if (mSweptAngle > 1f) {
canvas.clipPath(mArcPath)
mRingDrawable.draw(canvas)
canvas.restore()
}