From 54585e54657372023cb34b8a3b8f2150d84a5a59 Mon Sep 17 00:00:00 2001 From: Brijesh Barasiya Date: Wed, 28 Feb 2024 15:11:47 +0530 Subject: [PATCH] Circular Progress bar --- .../project.pbxproj | 4 + .../SSSwiftUIAnimations/ContentView.swift | 7 +- .../ProgressBar/SwiftUIView.swift | 136 ++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 SSSwiftUIAnimations/SSSwiftUIAnimations/LoadingAnimation/ProgressBar/SwiftUIView.swift diff --git a/SSSwiftUIAnimations/SSSwiftUIAnimations.xcodeproj/project.pbxproj b/SSSwiftUIAnimations/SSSwiftUIAnimations.xcodeproj/project.pbxproj index b6c84e3..67a5863 100644 --- a/SSSwiftUIAnimations/SSSwiftUIAnimations.xcodeproj/project.pbxproj +++ b/SSSwiftUIAnimations/SSSwiftUIAnimations.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 22AA9A5D2B67A065002FC677 /* Stick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22AA9A5C2B67A065002FC677 /* Stick.swift */; }; 22AA9A5F2B67A0DA002FC677 /* CircularProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22AA9A5E2B67A0DA002FC677 /* CircularProgressBar.swift */; }; 22AA9A612B67A0EF002FC677 /* LinearProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22AA9A602B67A0EF002FC677 /* LinearProgressBar.swift */; }; + 22C2680E2B8F284100ECC448 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22C2680D2B8F284100ECC448 /* SwiftUIView.swift */; }; 2BC2D8F328CF3A6F00CAB302 /* SSSwiftUIAnimationsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BC2D8F228CF3A6F00CAB302 /* SSSwiftUIAnimationsApp.swift */; }; 2BC2D8F528CF3A6F00CAB302 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BC2D8F428CF3A6F00CAB302 /* ContentView.swift */; }; 2BC2D8F728CF3A7000CAB302 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2BC2D8F628CF3A7000CAB302 /* Assets.xcassets */; }; @@ -30,6 +31,7 @@ 22AA9A5C2B67A065002FC677 /* Stick.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stick.swift; sourceTree = ""; }; 22AA9A5E2B67A0DA002FC677 /* CircularProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularProgressBar.swift; sourceTree = ""; }; 22AA9A602B67A0EF002FC677 /* LinearProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinearProgressBar.swift; sourceTree = ""; }; + 22C2680D2B8F284100ECC448 /* SwiftUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = ""; }; 2BC2D8EF28CF3A6F00CAB302 /* SSSwiftUIAnimations.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SSSwiftUIAnimations.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2BC2D8F228CF3A6F00CAB302 /* SSSwiftUIAnimationsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSSwiftUIAnimationsApp.swift; sourceTree = ""; }; 2BC2D8F428CF3A6F00CAB302 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -75,6 +77,7 @@ children = ( 22AA9A602B67A0EF002FC677 /* LinearProgressBar.swift */, 22AA9A5E2B67A0DA002FC677 /* CircularProgressBar.swift */, + 22C2680D2B8F284100ECC448 /* SwiftUIView.swift */, ); path = ProgressBar; sourceTree = ""; @@ -187,6 +190,7 @@ files = ( 2BC2D8F528CF3A6F00CAB302 /* ContentView.swift in Sources */, 22AA9A612B67A0EF002FC677 /* LinearProgressBar.swift in Sources */, + 22C2680E2B8F284100ECC448 /* SwiftUIView.swift in Sources */, 22AA9A572B679FEC002FC677 /* LoadingObservable.swift in Sources */, 22AA9A5F2B67A0DA002FC677 /* CircularProgressBar.swift in Sources */, 22AA9A5B2B67A03B002FC677 /* LinearLoading.swift in Sources */, diff --git a/SSSwiftUIAnimations/SSSwiftUIAnimations/ContentView.swift b/SSSwiftUIAnimations/SSSwiftUIAnimations/ContentView.swift index c39ac78..470c3ab 100644 --- a/SSSwiftUIAnimations/SSSwiftUIAnimations/ContentView.swift +++ b/SSSwiftUIAnimations/SSSwiftUIAnimations/ContentView.swift @@ -9,8 +9,11 @@ import SwiftUI struct ContentView: View { var body: some View { - Text("Hello, world!") - .padding() + VStack { + LoadingView(loaderType: .linearProgressBar(percentange: .constant(45), stickHeight: 100)) + .frame(height: 100) + Text("Hello") + } } } diff --git a/SSSwiftUIAnimations/SSSwiftUIAnimations/LoadingAnimation/ProgressBar/SwiftUIView.swift b/SSSwiftUIAnimations/SSSwiftUIAnimations/LoadingAnimation/ProgressBar/SwiftUIView.swift new file mode 100644 index 0000000..910a269 --- /dev/null +++ b/SSSwiftUIAnimations/SSSwiftUIAnimations/LoadingAnimation/ProgressBar/SwiftUIView.swift @@ -0,0 +1,136 @@ +// +// SwiftUIView.swift +// SSSwiftUIAnimations +// +// Created by Brijesh Barasiya on 28/02/24. +// + +import SwiftUI + +struct SwiftUIView: View { + @Binding private var percentage: Float + @State private var sticks: [Stick] + @State private var lastStickIndex: Int = 0 + private let circleRadius: CGFloat + private let stickWidth: CGFloat + private let filledColor: Color + private let unFilledColor: Color + private let duration: Double + private let progressColor: Color + + init( + percentage: Binding, + size: Float, + stickWidth: Float, + progressColor: Color, + filledColor: Color, + unFilledColor: Color, + duration: Double + ) { + let screenBounds = UIScreen.main.bounds + let screenWidth = Float(screenBounds.width) + let screenHeight = Float(screenBounds.height) + + // Adjust stick size, ensuring it doesn't exceed the screen size - 50 + let adjustedSize: Float = min(max(size, 50), min(screenWidth, screenHeight) - 50) + + // Adjust stick width, ensuring a minimum value of 9% of size. + let adjustedStickWidth = min(max((adjustedSize / 100) * 5, stickWidth), (adjustedSize / 100) * 20) + + let circumference = 2 * .pi * adjustedSize + let spacing = circumference / adjustedStickWidth + let totalStickCount: Int = Int((spacing * 25) / 100) + self.sticks = Array(repeating: Stick(xAxis: 0, color: unFilledColor), count: totalStickCount) + self.circleRadius = CGFloat(adjustedSize/2) + self.stickWidth = CGFloat(adjustedStickWidth) + self.progressColor = progressColor + self.filledColor = filledColor + self.unFilledColor = unFilledColor + self.duration = duration / Double(totalStickCount) + self._percentage = percentage + } + + var body: some View { + Circle() + .frame(width: circleRadius * 2) + .foregroundColor(Color.clear) + .overlay { + ForEach(0..= numberOfSticksToChange ? numberOfSticksToChange : lastStickIndex + lastStickIndex = finalIndex + } + + private func resertStickViewAnimation(index: Int, isReversing: Bool) { + withAnimation(Animation.linear(duration: duration)) { + sticks[index].xAxis = 0 + } + let nextIndex = isReversing ? index - 1 : index + 1 + if (index == (lastStickIndex) && isReversing) || (index == sticks.indices.last && !isReversing) { + animateStickView(index: isReversing ? nextIndex + 1 : nextIndex - 1, isReversing: !isReversing) + } else { + animateStickView(index: nextIndex ,isReversing: isReversing) + } + } + + private func getStickColor(forIndex index: Int, isReversing: Bool) -> Color { + return if (index == lastStickIndex) { + filledColor + } else if (index == sticks.indices.last) { + unFilledColor + } else { + (isReversing ? unFilledColor : filledColor) + } + } +} + +#Preview { + SwiftUIView( + percentage: .constant(76), + size: 100, + stickWidth: 3, + progressColor: .green, + filledColor: .blue, + unFilledColor: .gray, + duration: 5 + ) +}