13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SwiftUIで作るプログレス

Last updated at Posted at 2020-12-18

はじめに

この記事はDiverse Advent Calendar 2020の18日目の記事です。
業務でいくつかプログレスを作ったので紹介します。
同じようなデザインのプログレスを作る際はぜひご活用ください!

GitHubにこの記事のサンプルを上げてます。
↓実際に動きを見たい方はこちら
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, // プログレスの角を丸くしたい場合は.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

Shapeを継承してPieShapeというものを作っています。
Shapeを自作した場合、アニメーションが適用されないので animatableData をoverrideする必要があります。


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

Rectangleを2つ重ねて上のRectangleのwidthをvalueに応じて変えることで実現してます。
Squareと名付けてますがcornerRadiusを指定して角丸にすることもできます。

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(self.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) 角丸も可
        .onAppear {
            withAnimation(.linear(duration: 5)) {
                self.value = 1.0
            }
        } 
}

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

さいごに

今回は作成したプログレスを3つ紹介しました。
基本的にコピペで使えると思いますのでぜひご活用ください。

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?