Android自定义View–转圈圈

看GIF图说话,用代码实现这个效果
先以圆心a 画半径100的圆,在画一个半径150的圆c,以圆c上的点为半径画圆b,每隔5度画一个圆b,之后根据画圆b时的角度在圆b上画一个圆d,当大于180度时画圆的角度要用360度减去当前的度数。
首先肯定是测量View的大小了
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var w = 0
var h = 0
val wMode = MeasureSpec.getMode(widthMeasureSpec)
if (wMode == MeasureSpec.AT_MOST) {
w = widthC+paddingLeft+paddingRight
} else if (wMode == MeasureSpec.EXACTLY) {
w = MeasureSpec.getSize(widthMeasureSpec)+paddingLeft+paddingRight
}
val hMode = MeasureSpec.getMode(heightMeasureSpec)
if (hMode == MeasureSpec.AT_MOST) {
h = hightC+paddingTop+paddingBottom
} else if (hMode == MeasureSpec.EXACTLY) {
h = MeasureSpec.getSize(heightMeasureSpec)+paddingTop+paddingBottom
}
widthC = w
hightC = h
setMeasuredDimension(
MeasureSpec.makeMeasureSpec(w, wMode),
MeasureSpec.makeMeasureSpec(h, hMode)
)
}
计算圆上的坐标
pointX = x + radius * Math.cos(Math.toRadians(angle))//angle是弧度
pointY = y + radius * Math.sin(Math.toRadians(angle))
画出圆b
val realW = widthC - paddingLeft - paddingRight
val realH = hightC - paddingTop - paddingBottom
val centerRadius: Double = min(realW, realH) * 0.1875 //0.1875是计算圆c的半径 一个比例 150/800=0.1875
val circleRadius=min(realW, realH) * 0.3125 //0.3125是计算圆b的半径的一个比例 250/800=0.3125
for (i in 0..360 step 5) {//每5度画一个圆
val circleX =
((centerRadius * cos(
Math.toRadians(
i.toDouble()
)
)) + widthC / 2f).toFloat()
val circleY =
((centerRadius * sin(Math.toRadians(i.toDouble()))) + hightC / 2f).toFloat()
canvas?.drawCircle(circleX, circleY, circleRadius.toFloat(), circlePaint)
}
通过上面画出一下的圆
在通过一下代码将圆d画到圆b上
canvas?.drawCircle(
((circleRadius * cos(
Math.toRadians(
if (i in 0..180 && i == 360) getOffset(i) else getOffset(
360 - i
)
)
)) + circleX).toFloat(),
(circleRadius * sin(
Math.toRadians(
if (i in 0..180 && i == 360) getOffset(i) else getOffset(
360 - i
)
)
) + circleY).toFloat(),
5f,
dotPaint
)
/**
*@param i
* @param s 圆点的初始角度 默认0
*/
private fun getOffset(i: Int,s:Int=0): Double = (if (i == 360) {
0 + offset % 360+s
} else {
i + offset % 360+s
}).toDouble()
这样就画好了,如下图
最后去掉蓝色圆,添加计时器每16ms重绘一次,这样就可以动起来了
private var offset = 360
Timer().schedule(object : TimerTask() {
override fun run() {
offset++
invalidate()
}
}, 16, 16)
还可以弄成下面的样式:


网友评论