Progress made with Swift UI

Introduction

This article is the 18th day article of Diverse Advent Calendar 2020. I made some progresses in my work, so I will introduce them. Please use it when you make a progress with a similar design!

I have a sample of this article on GitHub. ↓ Click here if you want to see the actual movement https://github.com/Masataka-n/SwiftUIProgress

Ring

struct RingProgressView: View {

    var value: CGFloat
    var lineWidth: CGFloat = 6.0
    var outerRingColor: Color = Color.black.opacity(0.08)
    var innerRingColor: Color = Color.orange

    var body: some View {
        ZStack {
            Circle()
                .stroke(lineWidth: self.lineWidth)
                .foregroundColor(self.outerRingColor)
            Circle()
                .trim(from: 0.0, to: CGFloat(min(self.value, 1.0)))
                .stroke(
                    style: StrokeStyle(
                        lineWidth: self.lineWidth,
                        lineCap: .square, //If you want to round the corners of the progress.round
                        lineJoin: .round
                    )
                )
                .foregroundColor(self.innerRingColor)
                .rotationEffect(.degrees(-90.0))
        }
        .padding(.all, self.lineWidth / 2)
    }
}
@State var value: CGFloat = 0.0

 var body: some View {
    RingProgressView(value: value)
        .frame(width: 150, height: 150)
        .onAppear {
            withAnimation(.linear(duration: 5)) {
                self.value = 1.0
            }
        }        
}

ezgif.com-gif-maker (2).gif

Pie

I inherited Shape and made something called Pie Shape. If you create your own Shape, you will need to override animatableData as the animation will not be applied.


struct PieProgressView: View {

    var value: CGFloat

    var body: some View {
        ZStack {
            Circle()
                .fill(Color.black.opacity(0.08))
            PieShape(progress: value)
                .fill(Color.orange)
                .rotationEffect(.degrees(-90))
        }
    }
}

struct PieShape: Shape {

    var value: CGFloat

    var animatableData: CGFloat {
        get { value }
        set { value = newValue }
    }

    func path(in rect: CGRect) -> Path {
        Path { path in
            let center = CGPoint(x: rect.midX, y: rect.midY)
            path.move(to: center)
            path.addArc(
                center: center,
                radius: rect.width / 2,
                startAngle: .degrees(0),
                endAngle: .degrees(Double(360 * value)),
                clockwise: false
            )
            path.closeSubpath()
        }
    }
}


@State var value: CGFloat = 0.0

var body: some View {
    PieProgressView(value: value)
        .frame(width: 150, height: 150)
        .onAppear {
            withAnimation(.linear(duration: 5)) {
                self.value = 1.0
            }
        } 
}

ezgif.com-gif-maker.gif

Square

It is realized by stacking two Rectangles and changing the width of the above Rectangle according to the value. We call it Square, but you can also specify cornerRadius to round the corners.

struct SquareProgressView: View {

    var value: CGFloat
    var baseColor: Color = Color.black.opacity(0.08)
    var progressColor: Color = Color.orange

    var body: some View {
        GeometryReader { geometry in
            VStack(alignment: .trailing) {
                ZStack(alignment: .leading) {
                    Rectangle()
                        .fill(self.baseColor)
                    Rectangle()
                        .fill(Color.progressColor)
                        .frame(minWidth: 0, idealWidth:self.getProgressBarWidth(geometry: geometry),
                               maxWidth: self.getProgressBarWidth(geometry: geometry))
                }
            }
        }
    }

    func getProgressBarWidth(geometry:GeometryProxy) -> CGFloat {
        let frame = geometry.frame(in: .global)
        return frame.size.width * value
    }
}

@State var value: CGFloat = 0.0

var body: some View {

    SquareProgressView(value: value)
        .frame(height: 20)
        //.cornerRadius(10)Rounded corners are also possible
        .onAppear {
            withAnimation(.linear(duration: 5)) {
                self.value = 1.0
            }
        } 
}

ezgif.com-gif-maker (3).gif

at the end

This time, I introduced three progresses I created. I think that you can basically use it with copy and paste, so please use it.

Recommended Posts

Progress made with Swift UI
Shiritori map app made with Swift UI
Starting with Swift Swift UI
Swift UI 100 knocks
Customize View with View Modifier in Swift UI
I tried using Realm with Swift UI
[Swift] Create an image selection UI with PhotoKit
Incorporate View created with Swift UI into ViewController
Swift UI TextView placeholder
Getting Started with Swift
Display 3D objects of SceneKit with Swift UI, etc.
Execute external command with swift
Photo library in Swift UI
Presentation slides made with Processing
[Swift UI] Use Map view
Compare Java 8 Optional with Swift
Pokemon Go made with Faker Gem
[Android] Visualize progress etc. with Progressbar
I made a GUI with Swing
Make a Christmas tree with swift
Create Master Detail in Swift UI
Micro benchmark made with JFR API
[Swift 5] Implement UI for review function
Implementing side menus in Swift UI
Swift beginner Debugging memo with Xcode
Run an application made with Java8 with Java6