Swift中使用Bezier Path绘制日期关联进度圆的角度问题
解决自定义TableViewCell进度圆角度不匹配的问题
Hey,我帮你排查了下代码,核心问题出在角度计算的比例逻辑错误——你硬写了* 0.1这个固定系数,这只有当你默认最大间隔天数是10的时候才会凑效,但完全不符合你“date1越接近date2,圆越完整,间隔0天显示满圆”的需求。咱们一步步来修正:
先理清楚你的需求逻辑
你要的效果是:
- 当date1和date2间隔天数为0(同一天)→ 显示完整的360度圆
- 当date1和date2间隔天数越多 → 圆的填充进度越少
那正确的进度比例应该是:进度 = 1 - (当前间隔天数 / 你预设的最大间隔天数)。这里的“最大间隔天数”需要根据你的业务场景来定,比如如果是一个30天的任务周期,那最大间隔天数就是30——当间隔天数达到30时,圆完全空着;间隔0天时,圆完全填满。
修正后的代码实现
首先要改掉硬编码的系数,同时处理强制解包的风险,还要解决cell复用导致的图层叠加问题:
// 先安全获取间隔天数,别用强制解包,容易崩 guard let intervalDays = components.day else { // 如果获取不到间隔天数,直接显示空圆或者做其他处理 return } // 这里替换成你的业务场景中的最大间隔天数,比如30天 let totalDays = 30 // 计算进度比例:确保比例不会小于0(比如间隔天数超过总天数时,显示0进度) let progressRatio = max(0.0, 1.0 - Double(intervalDays)/Double(totalDays)) // 角度计算:从12点钟方向(-π/2)开始,顺时针绘制对应比例的圆弧 let startAngle = CGFloat(-Double.pi/2) let endAngle = startAngle + CGFloat(2 * Double.pi * progressRatio) // 创建圆弧路径 let circlePath = UIBezierPath( arcCenter: CGPoint(x: 80, y: 80), radius: 60, startAngle: startAngle, endAngle: endAngle, clockwise: true ) // 创建形状图层 let shapeLayer = CAShapeLayer() shapeLayer.path = circlePath.cgPath shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.strokeColor = UIColor.green.cgColor shapeLayer.lineWidth = 10.0 // 重点:TableViewCell复用的时候,要先移除旧的形状图层,不然会叠加 cell.progressView.layer.sublayers?.filter { $0 is CAShapeLayer }.forEach { $0.removeFromSuperlayer() } cell.progressView.layer.addSublayer(shapeLayer)
额外优化建议
- 动态颜色调整:可以根据进度比例改变描边颜色,让状态更直观:
let strokeColor: UIColor switch progressRatio { case ..<0.3: strokeColor = .systemRed case 0.3..<0.7: strokeColor = .systemYellow default: strokeColor = .systemGreen } shapeLayer.strokeColor = strokeColor.cgColor - 避免硬编码位置和半径:把
CGPoint(x:80,y:80)和radius:60改成基于progressView的frame计算,比如arcCenter: CGPoint(x: progressView.bounds.midX, y: progressView.bounds.midY),这样适配不同尺寸的视图更灵活。
为什么你的原代码不对?
原代码里的endAngle = -π/2 + 2π * 间隔天数 * 0.1逻辑完全反了:它是间隔天数越多,圆弧越长,10天的时候才会显示满圆,和你“间隔0天显示满圆”的需求正好相反。而且硬写的0.1没有任何业务依据,只能适配固定10天的场景,完全不通用。
内容的提问来源于stack exchange,提问作者tloz1506996
相关产品推荐
相关产品推荐

