Quantcast
Channel: Recent Questions - Stack Overflow
Viewing all articles
Browse latest Browse all 12111

SwiftUI semicircular interactive progress bar

$
0
0

Hi I am trying to develop a semi circular interactive progress bar using swift UI but am not able to get the expected output I am trying to achieve something similar to this

enter image description here

Here is my code

import SwiftUIstruct SemiCircularProgressBar: View {    @State var progressValue: Float = 0.0    @State private var degrees: Double = -90    var body: some View {        VStack {            ZStack {                ProgressBar(progress: self.$progressValue)                    .frame(width: 250.0, height: 250.0)                    .padding(40.0)                ProgressThumb(progress: self.$progressValue)                    .frame(width: 30, height: 30)                    .offset(x: self.thumbOffset().x, y: self.thumbOffset().y)                    .rotationEffect(.degrees(54.5))                    .gesture(                        DragGesture()                            .onChanged { gesture in                                let angle = self.angle(for: gesture.location)                                self.updateProgress(for: angle)                            }                    )            }            Spacer()        }    }    private func angle(for location: CGPoint) -> Double {        let vector = CGVector(dx: location.x, dy: location.y)        let angle = atan2(vector.dy, vector.dx)        return Double(angle * 180 / .pi)    }    private func updateProgress(for angle: Double) {        let totalAngle: Double = 220        let minAngle: Double = -110        let maxAngle: Double = minAngle + totalAngle        var normalizedAngle = min(max(minAngle, angle), maxAngle)        if normalizedAngle > 88.8 {            normalizedAngle = 88.8        }        let progress = Float((normalizedAngle - minAngle) / totalAngle)        self.progressValue = progress        self.degrees = normalizedAngle    }    private func thumbOffset() -> CGPoint {        let thumbRadius: CGFloat = 125 // half of progress bar diameter        let radians = CGFloat(degrees) * .pi / -100        let x = thumbRadius * cos(radians)        let y = thumbRadius * sin(radians)        return CGPoint(x: x, y: y)    }}struct ProgressBar: View {    @Binding var progress: Float    var body: some View {        ZStack {            Circle()                .trim(from: 0.3, to: 0.9)                .stroke(style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round))                .opacity(0.3)                .foregroundColor(Color.gray)                .rotationEffect(.degrees(54.5))            Circle()                .trim(from: 0.3, to: CGFloat(self.progress))                .stroke(style: StrokeStyle(lineWidth: 12.0, lineCap: .round, lineJoin: .round))                .fill(AngularGradient(gradient: Gradient(stops: [                    .init(color: Color(hex: "ED4D4D"), location: 0.39000002),                    .init(color: Color(hex: "E59148"), location: 0.48000002),                    .init(color: Color(hex: "EFBF39"), location: 0.5999999),                    .init(color: Color(hex: "EEED56"), location: 0.7199998),                    .init(color: Color(hex: "32E1A0"), location: 0.8099997)]), center: .center))                .rotationEffect(.degrees(54.5))            VStack {                Text("824").font(Font.system(size: 44)).bold().foregroundColor(Color(hex: "314058"))                Text("Great Score!").bold().foregroundColor(Color(hex: "32E1A0"))            }        }    }}struct ProgressThumb: View {    @Binding var progress: Float    var body: some View {        Circle()            .fill(Color.blue)            .frame(width: 30, height: 30)    }}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        )    }}#Preview {    SemiCircularProgressBar()}

Using this above code I am able to achieve something like thisenter image description here

The problems which I face here is like the thumb should be smooth and able to drag with in the semi circle. I am expecting a semicircle with a knob to show the progress. Thanks in advance


Viewing all articles
Browse latest Browse all 12111

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>