LoginSignup
0
1

【Swift】アニメーションプログレスバー

Posted at

イメージ

コード

import SwiftUI

struct CircularProgressBarView: View {
    @State var progress: CGFloat
    @State var percentage: Int = 0
    @State var isProgress: Bool = false
    var body: some View {
        ZStack {
            // 背景の円
            Circle()
            // 円形の線描写するように指定
                .stroke(lineWidth: 12)
                .foregroundColor(.mint.opacity(0.15))
            
            // 進捗を示す円
            Circle()
                .trim(from: 0.0, to: min(isProgress ? progress : 0, 1.0))
                // 線の端の形状などを指定
                .stroke(style: StrokeStyle(lineWidth: 16, lineCap: .round, lineJoin: .round))
                .fill(LinearGradient(gradient: Gradient(colors: [.blue, .mint]),
                                     startPoint: .top,
                                     endPoint: .bottom))
                .rotationEffect(Angle(degrees: 270))
            
            // 進捗率のテキスト
            AnimationReader(percentage) {value in
                Text("\(value) %")
                    .font(.system(size: 26))
                    .bold()
            }
        }
        .frame(width: 100, height: 100)
        .padding(32.0)
        .onAppear {
            withAnimation(.easeInOut(duration: 1)) {
                isProgress = true
                percentage += Int(progress * 100)
            }
        }
    }
}

struct CircularProgressBarView_Previews: PreviewProvider {
    static var previews: some View {
        CircularProgressBarView(progress: 0.8)
    }
}

fileprivate struct AnimationReaderModifier<Body: View>: AnimatableModifier {
    let content: (CGFloat) -> Body
    var animatableData: CGFloat
    
    init(value: CGFloat, @ViewBuilder content: @escaping (CGFloat) -> Body) {
        self.animatableData = value
        self.content = content
    }
    
    func body(content: Content) -> Body {
        self.content(animatableData)
    }
}

struct AnimationReader<Content: View>: View {
    
    let value: CGFloat
    let content: (_ animatingValue: CGFloat) -> Content
    
    init(_ observedValue: Int, @ViewBuilder content: @escaping (_ animatingValue: Int) -> Content) {
        self.value = CGFloat(observedValue)
        self.content = { value in content(Int(value)) }
    }
    
    init(_ observedValue: CGFloat, @ViewBuilder content: @escaping (_ animatingValue: CGFloat) -> Content) {
        self.value = observedValue
        self.content = content
    }
    
    var body: some View {
        EmptyView()
            .modifier(AnimationReaderModifier(value: value, content: content))
    }
}

参考資料

数値のアニメーション
プログレスバー

0
1
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
0
1