Держитесь крепче, это требует математики!
Предполагается, что центр вашего круга (0, 0).Допустим, у вас есть точка (x, y), лежащая на окружности, вы можете использовать функцию atan2 или arctan2 , чтобы получить угол (в радианах; радиан - это то, что вы хотите, так как UIBezierPath
используетрадианы ) точка лежит относительно центра круга.Таким образом, под этим углом вы знаете, куда по окружности вашего круга прикоснулся пользователь (назовите это touch angle
).Вы можете использовать это как endAngle
на UIBezierPath
.
Примечание: Если центр вашего круга не (0, 0), а (x1, y1), компенсировать его, вычтя разницу из точек касания (x, y), т.е.новые точки (x - x1, y - y1)
Если вы хотите указать процент от длины окружности, которую точка покрывает от 0 радов,Вы можете использовать формулу percentage = (touch angle*(in rads)* * 100)/2π)
.
Подробнее о atan2 / arctan2
Вы можете рассчитать угол касания по формуле touch angle = tan^(-1)(y/x)
ака touch angle = arctan2(y,x)
.Где (x, y) - это точки, по которым пользователь коснулся окружности.
Пример и пояснение (Правка)
Ладно тьфу , после некоторых исследований я понял это. посмотрите на этот код , обратите внимание на функцию touchesBegan(_ ...
.
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
for touch in touches {
let point = touch.location(in: self)
if backCircleBezierPath!.contains(point) {
print("contains")
let centeredPoint = CGPoint(x: (point.x - frame.width/2), y: (point.y - frame.height/2))
print(centeredPoint)
var rads = atan(centeredPoint.y/centeredPoint.x)
if centeredPoint.x < 0 {
rads += CGFloat.pi
} else if centeredPoint.x > 0 && centeredPoint.y < 0 {
rads += CGFloat.pi * 2
}
let perc = (rads - backCircleStartAngle) / abs(backCircleStartAngle - backCircleEndAngle)
frontCircleShapeLayer?.strokeEnd = perc
}
}
}
Я использовал CAShapeLayer
вместо рисования в draw(_ rect...
;Я рекомендую вам сделать то же самое.Ваш путь тоже работает хорошо, но с некоторыми изменениями, о которых я упомяну в конце.
Я использовал две дуги: 1. Дуга заполнителя - backCircleShapeLayer
2. Дуга индикатора прогресса - frontCircleShapeLayer
Когда пользователь нажимает на дугу-заполнитель, мы можем вычислить угол (в радианах) и нарисовать дугу индикатора прогресса от start Angle
до touch Angle
, как упоминалось ранее ( использовать этот метод для рисования штрихов напрямуюс UIBezierPath
в draw(_ ...
методе ), но я использую эти значения для вычисления доли perc
(между 0 и 1) и использую это как stroke end
дуги прогресса.
Это приводит к интересному новому обучению.Значение atan(y/x)
зависит от домена ( За этим стоит математика, если вам интересно ).Так что , если вы касаетесь 4-го квадранта, вы добавляете 360˚ или 2π, а если вы находитесь во 2-м или 3-м квадранте, вы добавляете 180˚ или π .После этого добавления ваш touch angle
должен отражать идеальное значение.