由於專案需求,需要做個這種的東西來實現某種功能,我在網上找到了很多資料卻始終不行,最終和本公司的安卓商量出來這個方法,基本思想就是畫四十八個扇形,圍繞圓的中心繪製成這樣一個圓環,如圖所示:
我是繼承 UIControl 類來實現的,主要就是重寫它的 drawRect 方法,來繪製這個"圓", 不多說,看程式碼: 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