Я хочу создать кольцевую диаграмму с перекрытием одной стороны с закругленным углом. нравиться
Требование: начальный конец должен быть ниже предыдущей строки, а конечный конец должен быть выше следующей строки. Я устал это делать, но последний слой линии показывает оба сверху. Я пробовал с кодом ниже
private func drawCircle(){
var startAngle: CGFloat = .pi / -2
var endAngle: CGFloat = 0.0
drawableItems.forEach { (item) in
print(item.title)
print(startAngle)
let center = calculateCenter()
endAngle = startAngle + calculateAngles(item: item)
if endAngle > 2 * CGFloat.pi {
endAngle -= 2 * .pi
}
// Radius of the view
let radius: CGFloat = calculateRadius()
let arcWidth: CGFloat = self.arcWidth
let circlePath = UIBezierPath(arcCenter: center,
radius: radius/2 - arcWidth/2,
startAngle: startAngle,
endAngle: endAngle,
clockwise: true)
circlePath.lineCapStyle = .round
let shapeLayer: CAShapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.strokeColor = item.color.cgColor
shapeLayer.lineWidth = arcWidth
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = .round
layer.addSublayer(shapeLayer)
startAngle = endAngle
}
}
вывод дает, как показано ниже. в котором последний слой с зеленым цветом показывает оба конца сверху вместо одного ниже предыдущего и другого поверх следующего
пожалуйста, помогите мне сделать это.





Проблема в том, что вы рисуете простую дугу с толстой линией и закругленными концами. Два закругленных конца последней дуги всегда будут закрывать предыдущую и первую дуги.
Решение состоит в том, чтобы нарисовать дуги с вогнутым концом, не закрывающим выпуклый конец предыдущей дуги.
Следующее расширение UIBezierPath нарисует такую дугу:
extension UIBezierPath {
convenience init(
chartArcCenter center: CGPoint,
radius: CGFloat,
lineWidth: CGFloat,
startAngle: CGFloat,
endAngle: CGFloat,
clockwise: Bool
) {
self.init()
// Draw inner radius arc
addArc(withCenter: center, radius: radius - lineWidth/2, startAngle: startAngle, endAngle: endAngle, clockwise: clockwise)
// Draw convex endcap
var x = cos(endAngle) * radius + center.x
var y = sin(endAngle) * radius + center.y
addArc(withCenter: CGPoint(x: x, y: y), radius: lineWidth / 2, startAngle: endAngle - .pi, endAngle: endAngle, clockwise: !clockwise)
// Draw outer radius arc
addArc(withCenter: center, radius: radius + lineWidth/2, startAngle: endAngle, endAngle: startAngle, clockwise: !clockwise)
// Draw concave startcap
x = cos(startAngle) * radius + center.x
y = sin(startAngle) * radius + center.y
addArc(withCenter: CGPoint(x: x, y: y), radius: lineWidth / 2, startAngle: startAngle, endAngle: startAngle + .pi, clockwise: clockwise)
close()
}
}
Используйте это в своем коде вместо текущего вызова UIBezierPath. Вы также можете внести изменения в настройки рисования слоя формы.
Со всеми изменениями ваш метод становится:
private func drawCircle(){
var startAngle: CGFloat = .pi / -2
var endAngle: CGFloat = 0.0
// Radius of the view
let radius: CGFloat = calculateRadius()
let arcWidth: CGFloat = self.arcWidth
let center = calculateCenter()
drawableItems.forEach { (item) in
endAngle = startAngle + calculateAngles(item: item)
let circlePath = UIBezierPath(chartArcCenter: center,
radius: radius/2 - arcWidth/2,
lineWidth: arcWidth,
startAngle: startAngle,
endAngle: endAngle,
clockwise: true)
let shapeLayer: CAShapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = item.color.cgColor
layer.addSublayer(shapeLayer)
startAngle = endAngle
}
}
Также обратите внимание, что для блока if endAngle > 2 * CGFloat.pi { нет причин. Ничего страшного, если угол «заворачивается». А вычисления радиуса, ширины и центра нужно выполнить только один раз, поэтому нет необходимости в тех, кто находится внутри цикла.
вам, возможно, придется построить каждую фигуру самостоятельно из составляющих ее дуг. Вам нужно будет начертить каждую фигуру на миллиметровой бумаге, определить центр и радиус каждой дуги и построить заполненный путь для каждой секции.