由于项目需求,需要做个这种的东西来实现某种功能,我在网上找到了很多资料却始终不行,最终和本公司的安卓商量出来这个方法,基本思想就是画四十八个扇形,围绕圆的中心绘制成这样一个圆环,如图所示:
override func draw(_ rect: CGRect) {
var blockBeginAngle = degreesToRandinas(deg: beginAngle)
var blockEndAngle = degreesToRandinas(deg: beginAngle + blockAngle)
let context = UIGraphicsGetCurrentContext()
for index in 0..<blockCount {
drawImage(context: context!,
startAngle: blockBeginAngle,
endAngle: blockEndAngle,
colorIndex: index)
// 下一块的起始角度和终止角度
blockBeginAngle = blockBeginAngle + degreesToRandinas(deg: blockAngle + sweepAngle)
blockEndAngle = blockEndAngle + degreesToRandinas(deg: blockAngle + sweepAngle)
}
}
private func drawImage(context: CGContext,
startAngle: CGFloat,
endAngle: CGFloat,
colorIndex: Int) {
// 画扇形
context.addArc(center: CGPoint(x: pointX, y: pointY),
radius: outerRadius,
startAngle: startAngle,
endAngle: endAngle,
clockwise: false)
context.addArc(center: CGPoint(x: pointX, y: pointY),
radius: innerRadius,
startAngle: endAngle,
endAngle: startAngle,
clockwise: true)
context.closePath()
// 设置参数
context.setFillColor(fillOrUnFill[currentValueArr[(colorIndex + 36) % 48]].cgColor) // 填充扇形颜色
print((fillOrUnFill[currentValueArr[(colorIndex + 36) % 48]]))
// 绘制
context.drawPath(using: .fill)
}
context.addArc
这个方法,第一个参数:圆心,第二个参数:半径,第三个参数:开始弧度,第四个参数:结束弧度,第五个参数:false(顺时针), true(逆时针)。大概也就是这样子:context.addArc(center: 圆心, radius: 半径, startAngle: 开始弧度, endAngle: 结束弧度, clockwise: false|true)
其中,degreesToRandinas
是计算角度转弧度的,degreesToRandinas
是计算弧度转角度的,很多画圆都需要这两个方法,相信大家已经很熟悉了
private func degreesToRandinas(deg: CGFloat) -> CGFloat { // 角度转弧度
return (CGFloat(M_PI) / 180 * deg)
}
private func randinsToDegrees(rad: CGFloat) -> CGFloat { // 弧度转角度
return (180 / CGFloat(M_PI) * rad)
}
现在圆是画出来了,接下来就是手指滑动,颜色的变换了。 首先我是用的一个数组来装颜色的,大家可以随意弄多种颜色(如果大家弄的颜色过多的话,就需要自己算数组的下标哟)。这里我就弄了三种颜色,一种是方块默认的颜色,其余两种就是根据情况而定手指滑动的颜色。手指滑动小方块变色的第一步,就是算出手指滑动的是哪块方块,这里我是根据算弧度来确定的。首先,重写 UIControl 的手势开始和手势持续的方法:
// 手势开始
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
super.beginTracking(touch, with: event)
let point = touch .location(in: self)
moveHandles(point: point)
return true
}
// 手势持续中
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
super.continueTracking(touch, with: event)
let point = touch.location(in: self)
moveHandles(point: point)
self.sendActions(for: .valueChanged)
return true
}
moveHandles
这个方法就是变颜色的核心部分了
func moveHandles(point: CGPoint) {
let number = getPointLocation(touch: point)
if number != oldNumber {
if number >= 0 && number < 48 {
// 返回扇形颜色
if isNight == 1 {
currentValueArr[number] = currentValueArr[number] == 1 ? 0 : 1
}
if isNight == 2 {
currentValueArr[number] = currentValueArr[number] == 2 ? 0 : 2
}
if isNight == 3 {
currentValueArr[number] = currentValueArr[number] == 0 ? 0 : 3
}
}
oldNumber = number
}
self.setNeedsDisplay()
}
getPointLocation
这个方法返回的就是哪一个方块了
private func getPointLocation(touch: CGPoint) -> Int {
let centerPoint = CGPoint(x: self.pointX, y: self.pointY)
let ang = getAngle(center: centerPoint, touch: touch)
return Int(round(ang / 7.5))
}
// 计算角度
private func getAngle(center: CGPoint, touch: CGPoint) -> CGFloat {
let lenA = touch.x - center.x
let lenB = touch.y - center.y
let lenC = sqrt(lenA * lenA + lenB * lenB)
var ang = acos(lenA / lenC)
ang = randinsToDegrees(rad: ang)
ang = ang * (touch.y < center.y ? -1 : 1)
if ang < 0 {
ang = 361 + ang
}
ang = CGFloat(Int(ang + 270) % 360)
return ang
}
如此,就算完成了,调用的也很简单,下面是调用的代码:
circleLayer = CircleLayer(frame: CGRect(origin: CGPoint(x: 0, y: 100), size:
CGSize(width: self.view.bounds.width, height: self.view.bounds.width)))
self.view.addSubview(circleLayer)
附上完整demo