Swift中如何在CoreGraphics绘制的饼图扇区内添加文本?
解决饼图扇区内文本定位问题
要在每个饼图扇区中正确放置文本,核心是基于扇区的中间角度计算文本位置,同时调整文本的偏移半径避免超出扇区,以下是修改后的完整实现:
首先确保你已定义包含标签字段的Segment结构体:
struct Segment { let value: CGFloat let color: UIColor let label: String // 扇区对应的文本标签 }
然后修改draw(_:)方法,加入文本绘制逻辑:
override func draw(_ rect: CGRect) { guard let ctx = UIGraphicsGetCurrentContext() else { return } let radius = min(frame.size.width, frame.size.height) * 0.5 let viewCenter = CGPoint(x: bounds.midX, y: bounds.midY) let totalValue = segments.reduce(0, {$0 + $1.value}) var startAngle = -CGFloat.pi * 0.5 // 从顶部开始绘制饼图 // 文本样式配置,可按需调整字体、颜色 let textAttributes: [NSAttributedString.Key: Any] = [ .font: UIFont.systemFont(ofSize: 12), .foregroundColor: UIColor.white ] let textRadius = radius * 0.7 // 文本距离中心的半径,取饼图半径的70%避免超出扇区 for segment in segments { // 绘制饼图扇区 let endAngle = startAngle + 2 * .pi * (segment.value / totalValue) ctx.setFillColor(segment.color.cgColor) ctx.move(to: viewCenter) ctx.addArc(center: viewCenter, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false) ctx.fillPath() // 计算文本的中心位置 let midAngle = startAngle + (endAngle - startAngle) / 2 // 取扇区的中间角度 let textX = viewCenter.x + textRadius * cos(midAngle) let textY = viewCenter.y + textRadius * sin(midAngle) let textCenterPoint = CGPoint(x: textX, y: textY) // 让文本居中绘制在计算出的位置上 let textSize = segment.label.size(withAttributes: textAttributes) let textRect = CGRect( x: textCenterPoint.x - textSize.width / 2, y: textCenterPoint.y - textSize.height / 2, width: textSize.width, height: textSize.height ) segment.label.draw(in: textRect, withAttributes: textAttributes) startAngle = endAngle } }
关键逻辑说明
- 中间角度定位:用扇区起始角和结束角的平均值计算文本位置,确保文本落在扇区的中心线上,不会偏移到其他扇区。
- 文本半径调整:通过
radius * 0.7控制文本与圆心的距离,既不会太靠近圆心拥挤,也不会超出扇区边缘。 - 文本居中对齐:先计算文本自身尺寸,再将文本的中心与计算出的坐标点对齐,保证文本在扇区内居中显示。
小扇区文本重叠优化建议
如果遇到极小扇区导致文本重叠的情况,可以:
- 根据扇区角度动态调整字体大小(比如角度小于π/12时缩小字体或隐藏文本)
- 将小扇区的文本移到饼图外部,添加连接线指向对应扇区(需要额外实现连接线绘制逻辑)
内容的提问来源于stack exchange,提问作者Ozz
相关产品推荐
相关产品推荐

