Добавить тап по UIBezierPath
Нарисовал круг из 4-х дуг. Как я могу добавить тап по каждой из них?
Вот как я добавлял дуги
override func draw(_ rect: CGRect) {
var lastArcAngle = -CGFloat.pi
func addArc(color: UIColor, percentage: CGFloat, index: Int) {
let fullCircle = CGFloat.pi * 2
let arcAngle = fullCircle * percentage
let path = UIBezierPath(arcCenter: CGPoint(x: rect.width/2, y: rect.height/2), radius: 50, startAngle: lastArcAngle, endAngle: lastArcAngle + arcAngle, clockwise: true)
color.setStroke()
path.lineWidth = 20
path.stroke()
lastArcAngle += arcAngle
}
addArc(color: .red, percentage: 1.5 / 6.0, index: 1)
addArc(color: .green, percentage: 1.5 / 6.0, index: 2)
addArc(color: .blue, percentage: 1.5 / 6.0, index: 3)
addArc(color: .purple, percentage: 1.5 / 6.0,index: 4)
}
Ответы (1 шт):
Автор решения: schmidt9
→ Ссылка
Можно добавить для каждого сегмента контурные пути и проверять, попадает ли в них точка
import UIKit
class ArcsView: UIView {
private var hitTestPaths = [UIBezierPath]()
required init?(coder: NSCoder) {
super.init(coder: coder)
let recognizer = UITapGestureRecognizer(target: self, action: #selector(tap(_ :)))
addGestureRecognizer(recognizer)
}
override func draw(_ rect: CGRect) {
hitTestPaths = []
var lastArcAngle = -CGFloat.pi
func addArc(color: UIColor, percentage: CGFloat, index: Int) {
let fullCircle = CGFloat.pi * 2
let arcAngle = fullCircle * percentage
let path = UIBezierPath(arcCenter: CGPoint(x: rect.width/2, y: rect.height/2), radius: 50, startAngle: lastArcAngle, endAngle: lastArcAngle + arcAngle, clockwise: true)
color.setStroke()
path.lineWidth = 20
path.stroke()
lastArcAngle += arcAngle
// рисуем для проверки
UIColor.black.setStroke()
let outlinePath = hitTestPath(for: path)
outlinePath.stroke()
hitTestPaths.append(outlinePath)
}
addArc(color: .red, percentage: 1.5 / 6.0, index: 1)
addArc(color: .green, percentage: 1.5 / 6.0, index: 2)
addArc(color: .blue, percentage: 1.5 / 6.0, index: 3)
addArc(color: .purple, percentage: 1.5 / 6.0,index: 4)
}
@objc func tap(_ recognizer: UITapGestureRecognizer) {
let location = recognizer.location(in: self)
if let hitPath = (hitTestPaths.first { $0.contains(location) }) {
print("hit \(hitPath)")
}
}
func hitTestPath(for path: UIBezierPath) -> UIBezierPath {
let pathCopy = path.cgPath.copy(strokingWithWidth: 20, lineCap: .butt, lineJoin: .miter, miterLimit: 0)
return UIBezierPath(cgPath: pathCopy)
}
}
Дополнение
Если к тапам нужно привязать действия, то это можно сделать например как показан ниже - добавить структуру для хранения связанных данных
import UIKit
class ArcsView: UIView {
typealias ArcAction = () -> Void
struct ArcInfo {
var outlinePath: UIBezierPath
var action: ArcAction
}
private var arcInfos: [ArcInfo]!
required init?(coder: NSCoder) {
super.init(coder: coder)
let recognizer = UITapGestureRecognizer(target: self, action: #selector(tap(_ :)))
addGestureRecognizer(recognizer)
}
override func draw(_ rect: CGRect) {
arcInfos = []
var lastArcAngle = -CGFloat.pi
func addArc(color: UIColor, percentage: CGFloat, index: Int, action: @escaping ArcAction) {
let fullCircle = CGFloat.pi * 2
let arcAngle = fullCircle * percentage
let path = UIBezierPath(arcCenter: CGPoint(x: rect.width/2, y: rect.height/2), radius: 50, startAngle: lastArcAngle, endAngle: lastArcAngle + arcAngle, clockwise: true)
color.setStroke()
path.lineWidth = 20
path.stroke()
lastArcAngle += arcAngle
// рисуем для проверки
UIColor.black.setStroke()
let outlinePath = hitTestPath(for: path)
outlinePath.stroke()
arcInfos.append(ArcInfo(outlinePath: outlinePath, action: action))
}
addArc(color: .red, percentage: 1.5 / 6.0, index: 1) {
print("action 1")
}
addArc(color: .green, percentage: 1.5 / 6.0, index: 2) {
print("action 2")
}
addArc(color: .blue, percentage: 1.5 / 6.0, index: 3) {
print("action 3")
}
addArc(color: .purple, percentage: 1.5 / 6.0,index: 4) {
print("action 4")
}
}
@objc func tap(_ recognizer: UITapGestureRecognizer) {
let location = recognizer.location(in: self)
if let hitPath = (arcInfos.first { $0.outlinePath.contains(location) }) {
hitPath.action()
}
}
func hitTestPath(for path: UIBezierPath) -> UIBezierPath {
let pathCopy = path.cgPath.copy(strokingWithWidth: 20, lineCap: .butt, lineJoin: .miter, miterLimit: 0)
return UIBezierPath(cgPath: pathCopy)
}
}