使用UIBezierPath绘制饼图:如何让橙色路径末端置于绿色路径下方
解决UIBezierPath饼图末端覆盖问题
问题原因
你通过UIBezierPath的stroke方式绘制环形饼图,设置了lineCapStyle = .round,导致橙色路径的末端圆形端点延伸到绿色路径区域上方。要实现橙色末端在绿色下方的效果,需要调整绘制顺序和路径角度范围。
解决方案
1. 调整绘制顺序
将绿色路径放在橙色路径之后绘制,让绿色的起始端圆形端点自然覆盖橙色的末端区域。
2. 修正橙色路径的结束角度
由于lineCap = .round会在路径两端添加半径为lineWidth/2的圆形端点,橙色路径的结束角度需要提前一个小角度,避免它的圆形端点超出到绿色路径的范围。这个角度可通过几何计算得出:
// 计算端点圆形对应的圆心角(弧度) let lineWidth = main_view_width let radius = (self.frame.size.width - lineWidth)/2 let capAngle = asin((lineWidth/2) / radius)
调用橙色路径的绘制函数时,将结束角度减去capAngle:
// 假设原本橙色的end_angle是绿色的起始角度greenStartAngle drawBeizer(start_angle: orangeStartAngle, end_angle: greenStartAngle - capAngle, final_color: .orange) // 绿色路径从原本的起始角度开始绘制 drawBeizer(start_angle: greenStartAngle, end_angle: greenEndAngle, final_color: .green)
3. 可选:整合角度修正逻辑到绘制函数
可以把角度处理逻辑封装进绘制函数,让调用更简洁:
func drawBeizer(startAngle: CGFloat, endAngle: CGFloat, color: UIColor, isLastPath: Bool = false) { let lineWidth = main_view_width let radius = (self.frame.size.width - lineWidth)/2 let capAngle = asin((lineWidth/2) / radius) var adjustedEndAngle = endAngle // 非最后一条路径,结束角度提前,避免末端圆形超出 if !isLastPath { adjustedEndAngle -= capAngle } let path = UIBezierPath() path.addArc(withCenter: CGPoint(x: bounds.midX, y: bounds.midY), radius: radius, startAngle: startAngle, endAngle: adjustedEndAngle, clockwise: true) path.lineWidth = lineWidth path.lineCapStyle = .round color.setStroke() path.stroke() }
调用示例:
// 先绘制橙色(非最后一条路径) drawBeizer(startAngle: orangeStart, endAngle: greenStart, color: .orange, isLastPath: false) // 再绘制绿色(最后一条路径) drawBeizer(startAngle: greenStart, endAngle: greenEnd, color: .green, isLastPath: true)
原理说明
- 后绘制的路径会覆盖先绘制的路径,绿色在橙色之后绘制,其起始端的圆形端点能盖住橙色的末端。
- 提前橙色的结束角度,避免它的圆形端点延伸到绿色区域,确保绿色路径完全覆盖衔接处,达到目标效果。
内容的提问来源于stack exchange,提问作者Fahim Parkar
相关产品推荐
相关产品推荐

