search
LoginSignup
8
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

diverseDiverse Advent Calendar 2020 Day 18

posted at

updated at

Organization

SwiftUIで作るプログレス

はじめに

この記事は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つ紹介しました。
基本的にコピペで使えると思いますのでぜひご活用ください。

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
What you can do with signing up
8
Help us understand the problem. What are the problem?