StinkySocks
StinkySocks

Reputation: 924

SwiftUI: Change the start position for animated progress bar (or Shape drawing in general)

The code below begins to draw a rectangle from the bottom left corner. How can I change it to begin to draw from the top middle? Hopefully there is a simple setting I am missing here.

@State private var progress: Double = 0
@State private var timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()

var body: some View {
    VStack{
        HStack{
            ZStack {
                Rectangle()
                    .stroke(lineWidth: 20.0)
                    .opacity(0.3)
                    .foregroundColor(Color.gray)
                    .rotationEffect(Angle(degrees: 270.0))
                    .frame(width: 100, height:100)
                Rectangle()
                    .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                    .stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round))
                    .foregroundColor(Color.blue)
                    .rotationEffect(Angle(degrees: 270.0))
                    .animation(.linear)
                    .frame(width: 100, height:100)
                    .onReceive(timer, perform: { _ in
                        if(progress < 100){
                            progress += 0.1/10
                        }
                        else{
                            progress = 0
                        }
                    })
            }
        }
        .padding()
    }
}

Upvotes: 5

Views: 1250

Answers (1)

Asperi
Asperi

Reputation: 257693

You don't need to rotate it (moreover it might be not square), just create own rectangular shape with start point anywhere needed.

Demo prepared with Xcode 12.4 / iOS 14.4

demo

struct MyRectangle: Shape {
    func path(in rect: CGRect) -> Path {
        Path {
            $0.move(to: CGPoint(x: rect.midX, y: rect.minY))
            $0.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
            $0.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
            $0.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
            $0.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
            $0.addLine(to: CGPoint(x: rect.midX, y: rect.minY))
        }
    }
}

struct ContentView: View {
    @State private var progress: Double = 0
    @State private var timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()

    var body: some View {
        VStack{
            HStack{
                ZStack {
                    MyRectangle()
                        .stroke(lineWidth: 20.0)
                        .opacity(0.3)
                        .foregroundColor(Color.gray)
                        .frame(width: 200, height:100)
                    MyRectangle()
                        .trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
                        .stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round))
                        .foregroundColor(Color.blue)
                        .animation(.linear)
                        .frame(width: 200, height:100)
                        .onReceive(timer, perform: { _ in
                            if(progress < 100){
                                progress += 0.1/10
                            }
                            else{
                                progress = 0
                            }
                        })
                }
            }
            .padding()
        }
    }
}

Upvotes: 8

Related Questions