SwiftUI 环形进度条
struct RingShap: Shape { var pointSize: CGFloat = 10.0 func path(in rect: CGRect) -> Path { let drawRect = CGRectInset(rect, 0.5 * pointSize, 0.5 * pointSize) var path = Path() path.addArc(center: CGPoint(x: CGRectGetMidX(drawRect), y: CGRectGetMidY(drawRect)), radius: 0.5 * min(drawRect.size.width, drawRect.size.height), startAngle: Angle(degrees: 135), endAngle: Angle(degrees: 45), clockwise: false) return path } } struct RingClipShap: Shape { var blankCenter: CGPoint = CGPointZero var pointSize: CGFloat = 14.0 func path(in rect: CGRect) -> Path { let r = 0.5 * pointSize; let drawRect = CGRectInset(rect, -r, -r) var blankPath = Path() blankPath.addArc(center: blankCenter, radius: r, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 360), clockwise: true) var showPath = Path(roundedRect: drawRect, cornerSize: CGSizeZero) showPath.addPath(blankPath) return showPath } } public struct WeatherProgress: View { var strokeColor: Color = .red var pointColor: Color = .blue var progress: CGFloat = 0.5 var pointSize: CGFloat = 10.0 var extendPointSize: CGFloat = 4.0 public var body: some View { GeometryReader { geometry in RingShap(pointSize: pointSize) .stroke(.red, style: StrokeStyle(lineWidth: pointSize, lineCap: .round)) .frame(width: geometry.size.width, height: geometry.size.height) .clipShape(RingClipShap(blankCenter: progressPointCenter(geometry.size), pointSize: pointSize + extendPointSize)) Path { path in let centerPoint = progressPointCenter(geometry.size) path.move(to: centerPoint) path.addArc(center: centerPoint, radius: 0.5 * pointSize, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 360), clockwise: true) } .fill(pointColor) } .background(Color.clear) } func progressPointCenter(_ size: CGSize) -> CGPoint { let rect = CGRectMake(0.5 * pointSize, 0.5 * pointSize, size.width - pointSize, size.height - pointSize) let centerX = CGRectGetMidX(rect) let centerY = CGRectGetMidY(rect) let radius = 0.5 * min(rect.size.width, rect.size.height) let startAngle = Double.pi * (135.0 / 180.0) let endAngle = Double.pi * (45.0 / 180.0) let totalAngle = Double.pi * 2.0 - startAngle + endAngle var location = progress * totalAngle + startAngle if location > (Double.pi * 2.0) { location = location - Double.pi * 2.0 } let lcx = centerX + radius * cos(location) let lcy = centerY + radius * sin(location) return CGPoint(x: lcx, y: lcy) } }