SwiftUI半环形进度条右侧缩短实现及progress参数疑问咨询
半环形进度条右侧缩短方案及进度参数解析
问题背景
基于半环形进度条实现,已通过调整trim(from: 0.3)至0.35缩短左侧长度避免覆盖标签,现需缩短右侧长度,同时对CGFloat(self.progress)的作用存在疑问,要求不影响进度的准确展示。
先明确CGFloat(self.progress)的作用
Circle().trim(from:to:)的参数取值范围是**01**,对应整个圆形周长的比例:0代表圆形起点,1代表回到起点。这里的`progress`是01之间的Float值,转成CGFloat后用于控制进度条的终点位置:
- 当
progress=0.35时,进度条完全不显示; - 当
progress=0.85时,进度条填满当前背景环的全部范围。
缩短右侧长度的实现方案
当前背景环的to: 0.85是右侧终点,要缩短右侧只需将该值调小(比如改为0.8),但直接修改进度条的to参数会导致进度与背景环不匹配——因为原progress是对应0.35~0.85的范围。
核心思路:进度值映射
我们需要把0~1的progress值,映射到自定义的起始-结束区间内,公式如下:
进度终点 = 起始比例 + (结束比例 - 起始比例) * progress
这样无论起始/结束比例如何调整,progress=0时进度条停在起点,progress=1时刚好到达新的右侧终点,进度展示完全准确。
修改后的完整代码
struct ProgressBar: View { @Binding var progress: Float // 自定义进度条的起始/结束比例,可按需调整 private let startTrim: CGFloat = 0.35 private let endTrim: CGFloat = 0.8 // 调小此值即可缩短右侧长度 var body: some View { VStack{ Label("Address: 0000", systemImage: "target") .foregroundColor(Color(hex: "8f8f8f")) ZStack { // 背景环 Circle() .trim(from: startTrim, to: endTrim) .stroke(style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round)) .opacity(0.3) .foregroundColor(Color.gray) .rotationEffect(.degrees(54.5)) // 进度环(核心修改:进度值映射) Circle() .trim(from: startTrim, to: startTrim + (endTrim - startTrim) * CGFloat(progress)) .stroke(style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round)) .fill(AngularGradient(gradient: Gradient(stops: [ .init(color: Color.init(hex: "daff00"), location: 0.39000002), .init(color: Color.init(hex: "00ff04"), location: 0.5999999), .init(color: Color.init(hex: "32E1A0"), location: 0.8099997)]), center: .center)) .rotationEffect(.degrees(54.5)) VStack{ Text("824").font(Font.system(size: 44)).bold().foregroundColor(Color.init(hex: "ffffff")) Label("Please standby...", systemImage: "clock") .foregroundColor(Color(hex: "FF6600")) Label("Uploading memory model to controller", systemImage: "") .foregroundColor(Color(hex: "8f8f8f")) } } } } } struct ProgressBarTriangle: View { @Binding var progress: Float var body: some View { ZStack { Image("triangle").resizable().frame(width: 10, height: 10, alignment: .center) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } extension Color { init(hex: String) { let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int: UInt64 = 0 Scanner(string: hex).scanHexInt64(&int) let a, r, g, b: UInt64 switch hex.count { case 3: // RGB (12-bit) (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) case 6: // RGB (24-bit) (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) case 8: // ARGB (32-bit) (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) default: (a, r, g, b) = (1, 1, 1, 0) } self.init( .sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: Double(a) / 255 ) } }
关键修改说明
- 把起始、结束比例抽为常量
startTrim和endTrim,方便后续灵活调整; - 进度环的
to参数改为映射公式,确保进度值与自定义范围完全匹配; - 只需调整
endTrim的数值(比如从0.85改为0.8),即可实现右侧长度缩短,同时保证进度展示的准确性。
内容的提问来源于stack exchange,提问作者Summer
相关产品推荐
相关产品推荐

