-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
124ceb5
commit 431ba93
Showing
11 changed files
with
1,072 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
SSSwiftUIAnimations/Examples/ExampleSticksAnimations.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// | ||
// ExampleSticksAnimations.swift | ||
// SSSwiftUIAnimations | ||
// | ||
// Created by Brijesh Barasiya on 25/10/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct ExampleSticksAnimations: View { | ||
|
||
// MARK: - Variables | ||
@State private var percentage: Double = 0 | ||
|
||
var body: some View { | ||
VStack { | ||
Text("Horizontal Loading") | ||
.frame(maxWidth: .infinity, alignment: .leading) | ||
.padding(.leading, 20) | ||
StickAnimations(type: .linearLoading(), duration: 3) | ||
.frame(width: 200, height: 80) | ||
|
||
Spacer().frame(height: 20) | ||
|
||
Text("Circular Loading") | ||
.frame(maxWidth: .infinity, alignment: .leading) | ||
.padding(.leading, 20) | ||
StickAnimations(type: .circularLoading, duration: 3) | ||
.frame(width: 200, height: 80) | ||
|
||
Spacer().frame(height: 20) | ||
|
||
Text("Horizontal Progress") | ||
.frame(maxWidth: .infinity, alignment: .leading) | ||
.padding(.leading, 20) | ||
StickAnimations(type: .linearProgressBar(percentage: $percentage), duration: 3) | ||
.frame(width: 200, height: 80) | ||
|
||
Spacer().frame(height: 20) | ||
|
||
Text("Circular Progress") | ||
.frame(maxWidth: .infinity, alignment: .leading) | ||
.padding(.leading, 20) | ||
StickAnimations(type: .circularProgressBar(percentage: $percentage), duration: 3) | ||
.frame(width: 200, height: 80) | ||
|
||
Spacer().frame(height: 20) | ||
|
||
Text("Circular Reversable Progress") | ||
.frame(maxWidth: .infinity, alignment: .leading) | ||
.padding(.leading, 20) | ||
StickAnimations(type: .circularReversableProgressBar(percentage: $percentage), duration: 3) | ||
.frame(width: 200, height: 80) | ||
|
||
Slider(value: $percentage, in: 1...100) | ||
.padding(.horizontal, 30) | ||
}.customToolbar(title: "Stick Animations Example", fontSize: 17) | ||
} | ||
} | ||
|
||
#Preview { | ||
ExampleSticksAnimations() | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
SSSwiftUIAnimations/Sources/SticksAnimations/CircularLoading.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// | ||
// CircularLoading.swift | ||
// SSSwiftUIAnimations | ||
// | ||
// Created by Brijesh Barasiya on 29/01/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct CircularLoading: View { | ||
/// The sticks to be displayed in the loading indicator. | ||
@State private var sticks: [Stick] | ||
/// The size of the circle. | ||
private let circleSize: CGFloat | ||
/// The width of each stick. | ||
private let stickWidth: CGFloat | ||
/// The color of a filled stick. | ||
private let filledColor: Color | ||
/// The color of an unfilled stick. | ||
private let unFilledColor: Color | ||
/// The duration of the animation for each stick. | ||
private let perStickDuration: Double | ||
|
||
/// Initializes the `CircularLoading` view. | ||
/// - Parameters: | ||
/// - size: The size of the view. | ||
/// - filledColor: The color of a filled stick. | ||
/// - unFilledColor: The color of an unfilled stick. | ||
/// - duration: The total duration of the animation. | ||
init( | ||
size: CGSize, | ||
filledColor: Color, | ||
unFilledColor: Color, | ||
duration: Double | ||
) { | ||
let adjustedSize = min(size.width, size.height) | ||
let adjustedStickWidth = adjustedSize * 0.05 | ||
let totalStickCount: Int = Int(adjustedSize / (adjustedStickWidth * 0.75)) | ||
self.sticks = Array( | ||
repeating: Stick(xAxis: 0, stickHeight: (adjustedSize * 0.20), color: unFilledColor), | ||
count: totalStickCount | ||
) | ||
self.circleSize = CGFloat(adjustedSize) | ||
self.stickWidth = CGFloat(adjustedStickWidth) | ||
self.filledColor = filledColor | ||
self.unFilledColor = unFilledColor | ||
self.perStickDuration = duration / Double(totalStickCount) | ||
} | ||
|
||
var body: some View { | ||
Circle() | ||
.frame(width: circleSize) | ||
.foregroundColor(Color.clear) | ||
.overlay { | ||
ForEach(0..<sticks.count, id: \.self) { index in | ||
Rectangle() | ||
.frame(width: stickWidth, height: sticks[index].stickHeight) | ||
.foregroundColor(sticks[index].color) | ||
.offset(y: (circleSize - sticks[index].stickHeight) / 2) | ||
.rotationEffect( | ||
.degrees(Double((CGFloat(index) + sticks[index].xAxis) * 360) / Double(sticks.count)) | ||
) | ||
} | ||
} | ||
.onAppear { | ||
animateStickView(index: 0, color: filledColor) | ||
} | ||
} | ||
|
||
/// Starts and resets the animation on a particular stick view. | ||
/// - Parameters: | ||
/// - index: The index of the current stick. | ||
/// - color: The color to animate to. | ||
private func animateStickView(index: Int, color: Color) { | ||
if #available(iOS 17.0, *) { | ||
withAnimation(Animation.linear(duration: perStickDuration)) { | ||
updateStickViewProperties(index: index, color: color) | ||
} completion: { | ||
resetStickViewAnimation(index: index, color: color) | ||
} | ||
} else { | ||
withAnimation(Animation.linear(duration: perStickDuration)) { | ||
updateStickViewProperties(index: index, color: color) | ||
} | ||
DispatchQueue.main.asyncAfter(deadline: .now() + perStickDuration) { | ||
resetStickViewAnimation(index: index, color: color) | ||
} | ||
} | ||
} | ||
|
||
/// Updates the properties of the stick view for animation. | ||
/// - Parameters: | ||
/// - index: The index of the current stick. | ||
/// - color: The color to animate to. | ||
private func updateStickViewProperties(index: Int, color: Color) { | ||
sticks[index].xAxis = 0.6 | ||
sticks[index].color = color | ||
} | ||
|
||
/// Resets the properties of the stick view after animation. | ||
/// - Parameters: | ||
/// - index: The index of the current stick. | ||
/// - color: The color to animate to. | ||
private func resetStickViewAnimation(index: Int, color: Color) { | ||
withAnimation(Animation.linear(duration: perStickDuration * 10)) { | ||
sticks[index].xAxis = 0 | ||
} | ||
if index == sticks.indices.last { | ||
let newColor = switch color { | ||
case unFilledColor: filledColor | ||
case filledColor: unFilledColor | ||
default: filledColor | ||
} | ||
animateStickView(index: 0, color: newColor) | ||
} else { | ||
animateStickView(index: index + 1, color: color) | ||
} | ||
} | ||
} | ||
|
||
#Preview { | ||
CircularLoading( | ||
size: CGSize(width: 150, height: 150), | ||
filledColor: .black, | ||
unFilledColor: .gray, | ||
duration: 1 | ||
) | ||
} |
Oops, something went wrong.