Skip to content

Commit f2d8c97

Browse files
Merge pull request #11 from SimformSolutionsPvtLtd/feature/UNT-T26889-Water_effect_animation
UNT-T26889 - Add Water Effect Progress Animation View
2 parents c292ca4 + 6afefdf commit f2d8c97

File tree

10 files changed

+547
-1
lines changed

10 files changed

+547
-1
lines changed

SSSwiftUIAnimations.xcodeproj/project.pbxproj

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232
B1DFCA532BF4FC7900F01505 /* ArrowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DFCA522BF4FC7900F01505 /* ArrowView.swift */; };
3333
B1EA09DE2C11A6B70024BC28 /* Banner.png in Resources */ = {isa = PBXBuildFile; fileRef = B1EA09DD2C11A6B70024BC28 /* Banner.png */; };
3434
B1FE861E2BFF6BC000FB111C /* ViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FE861D2BFF6BC000FB111C /* ViewExtension.swift */; };
35+
B717EC9D2C45488100555F90 /* CheckmarkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B717EC9C2C45488100555F90 /* CheckmarkView.swift */; };
36+
B741D9A62C46448200ABFCB4 /* WaterProgressTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B741D9A52C46448200ABFCB4 /* WaterProgressTextView.swift */; };
37+
B780A9182C3D063500342512 /* WaterProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9172C3D063500342512 /* WaterProgressView.swift */; };
38+
B780A91A2C3D0BCB00342512 /* WaterProgressViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9192C3D0BCB00342512 /* WaterProgressViewStyle.swift */; };
39+
B780A9242C3D7A7C00342512 /* WaterCircleOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9232C3D7A7C00342512 /* WaterCircleOutlineView.swift */; };
40+
B780A9262C3D806300342512 /* ExampleWaterProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9252C3D806300342512 /* ExampleWaterProgressView.swift */; };
41+
B780A9282C3D851700342512 /* WaterCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9272C3D851700342512 /* WaterCircleView.swift */; };
42+
B7ECD58D2C452D8100B6A703 /* BubbleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7ECD58C2C452D8100B6A703 /* BubbleView.swift */; };
3543
/* End PBXBuildFile section */
3644

3745
/* Begin PBXFileReference section */
@@ -61,6 +69,14 @@
6169
B1DFCA522BF4FC7900F01505 /* ArrowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowView.swift; sourceTree = "<group>"; };
6270
B1EA09DD2C11A6B70024BC28 /* Banner.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Banner.png; sourceTree = "<group>"; };
6371
B1FE861D2BFF6BC000FB111C /* ViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtension.swift; sourceTree = "<group>"; };
72+
B717EC9C2C45488100555F90 /* CheckmarkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckmarkView.swift; sourceTree = "<group>"; };
73+
B741D9A52C46448200ABFCB4 /* WaterProgressTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterProgressTextView.swift; sourceTree = "<group>"; };
74+
B780A9172C3D063500342512 /* WaterProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterProgressView.swift; sourceTree = "<group>"; };
75+
B780A9192C3D0BCB00342512 /* WaterProgressViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterProgressViewStyle.swift; sourceTree = "<group>"; };
76+
B780A9232C3D7A7C00342512 /* WaterCircleOutlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterCircleOutlineView.swift; sourceTree = "<group>"; };
77+
B780A9252C3D806300342512 /* ExampleWaterProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleWaterProgressView.swift; sourceTree = "<group>"; };
78+
B780A9272C3D851700342512 /* WaterCircleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterCircleView.swift; sourceTree = "<group>"; };
79+
B7ECD58C2C452D8100B6A703 /* BubbleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleView.swift; sourceTree = "<group>"; };
6480
/* End PBXFileReference section */
6581

6682
/* Begin PBXFrameworksBuildPhase section */
@@ -154,6 +170,7 @@
154170
children = (
155171
B19E0B652BF7498700E65974 /* ExampleProgressView.swift */,
156172
B153FD142BFB7A7900AEFE83 /* ExampleLRArrowView.swift */,
173+
B780A9252C3D806300342512 /* ExampleWaterProgressView.swift */,
157174
B1F9ED332BFCD85000189871 /* ExamplesList */,
158175
);
159176
path = Examples;
@@ -162,6 +179,7 @@
162179
B1DE99D72C060E1A006995FB /* Sources */ = {
163180
isa = PBXGroup;
164181
children = (
182+
B780A9162C3D05CD00342512 /* WaterProgressAnimation */,
165183
B14AB36A2BC40286004B09C4 /* ProgressAnimation */,
166184
469963A3290FCE1900DC01AD /* ArrowLeftRightAnimation */,
167185
);
@@ -186,6 +204,20 @@
186204
path = ExamplesList;
187205
sourceTree = "<group>";
188206
};
207+
B780A9162C3D05CD00342512 /* WaterProgressAnimation */ = {
208+
isa = PBXGroup;
209+
children = (
210+
B780A9172C3D063500342512 /* WaterProgressView.swift */,
211+
B780A9192C3D0BCB00342512 /* WaterProgressViewStyle.swift */,
212+
B780A9232C3D7A7C00342512 /* WaterCircleOutlineView.swift */,
213+
B780A9272C3D851700342512 /* WaterCircleView.swift */,
214+
B7ECD58C2C452D8100B6A703 /* BubbleView.swift */,
215+
B717EC9C2C45488100555F90 /* CheckmarkView.swift */,
216+
B741D9A52C46448200ABFCB4 /* WaterProgressTextView.swift */,
217+
);
218+
path = WaterProgressAnimation;
219+
sourceTree = "<group>";
220+
};
189221
/* End PBXGroup section */
190222

191223
/* Begin PBXNativeTarget section */
@@ -273,10 +305,18 @@
273305
B15FD7992C04785700752CEA /* CustomToolBar.swift in Sources */,
274306
469963A5290FCE3600DC01AD /* SSLRArrowView.swift in Sources */,
275307
B153FD0C2BFB3C1800AEFE83 /* LRArrowAnimStyle.swift in Sources */,
308+
B717EC9D2C45488100555F90 /* CheckmarkView.swift in Sources */,
309+
B780A9282C3D851700342512 /* WaterCircleView.swift in Sources */,
276310
B153FD132BFB71F500AEFE83 /* FilledStrokeCircle.swift in Sources */,
277311
2BC2D8F328CF3A6F00CAB302 /* SSSwiftUIAnimationsApp.swift in Sources */,
312+
B741D9A62C46448200ABFCB4 /* WaterProgressTextView.swift in Sources */,
313+
B780A9242C3D7A7C00342512 /* WaterCircleOutlineView.swift in Sources */,
278314
B1DFCA532BF4FC7900F01505 /* ArrowView.swift in Sources */,
315+
B780A9182C3D063500342512 /* WaterProgressView.swift in Sources */,
279316
B11B983A2BCE9C3F00D76016 /* CheckView.swift in Sources */,
317+
B7ECD58D2C452D8100B6A703 /* BubbleView.swift in Sources */,
318+
B780A9262C3D806300342512 /* ExampleWaterProgressView.swift in Sources */,
319+
B780A91A2C3D0BCB00342512 /* WaterProgressViewStyle.swift in Sources */,
280320
B1DFCA512BF4FA3D00F01505 /* ProgressCircle.swift in Sources */,
281321
B14AB36C2BC41B05004B09C4 /* ProgressView.swift in Sources */,
282322
B1FE861E2BFF6BC000FB111C /* ViewExtension.swift in Sources */,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// ExampleWaterProgressView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Rahul Yadav on 09/07/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct ExampleWaterProgressView: View {
11+
12+
// MARK: - Variables
13+
@State private var progress: Double = 0.0
14+
15+
var body: some View {
16+
VStack {
17+
SSWaterProgressView(progress: $progress,
18+
showPercent: true,
19+
style: SSWaterProgressViewStyle(
20+
circleSize: 200,
21+
circleStrokeWidth: 10,
22+
progressFont: .system(size: 16, weight: .bold),
23+
progressTextColor: .black,
24+
emptyStrokeColor: .cyan.opacity(0.2),
25+
fillStrokeColor: .cyan,
26+
waterColor: .mint,
27+
showBubbles: true,
28+
bubbleColor: .white,
29+
checkMarkImg: "checkmark",
30+
checkMarkImgColor: .white
31+
),
32+
onProgressCompletion: { print("Progress Completed") })
33+
Spacer()
34+
.frame(height: 40)
35+
Slider(value: $progress) {
36+
Text("Slide to manage progress")
37+
}
38+
.frame(width: 150, alignment: .bottom)
39+
}
40+
.customToolbar(title: "Water ProgressView Example", fontSize: 17)
41+
}
42+
}
43+
44+
#Preview {
45+
ExampleWaterProgressView()
46+
}

SSSwiftUIAnimations/Examples/ExamplesList/ExampleListModel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ class ExampleListModel: Identifiable {
2121
}
2222

2323
// data for example row list
24-
static let exampleList = [ExampleListModel(rowTitle: "ProgressView", destinationView: AnyView(ExampleProgressView())), ExampleListModel(rowTitle: "Arrow Left Right View", destinationView: AnyView(ExampleLRArrowView()))]
24+
static let exampleList = [ExampleListModel(rowTitle: "ProgressView", destinationView: AnyView(ExampleProgressView())), ExampleListModel(rowTitle: "Arrow Left Right View", destinationView: AnyView(ExampleLRArrowView())), ExampleListModel(rowTitle: "Water Progress View", destinationView: AnyView(ExampleWaterProgressView()))]
2525
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// BubbleView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Rahul Yadav on 15/07/24.
6+
//
7+
8+
import SwiftUI
9+
10+
/// Create a view with Bubbles used in animation
11+
struct BubbleView: View {
12+
13+
// MARK: Variables
14+
15+
/// Used for styling the view
16+
@State var style: SSWaterProgressViewStyle = SSWaterProgressViewStyle()
17+
18+
/// Initial Bubble Scale
19+
@State private var scale : CGFloat = 1
20+
21+
var body: some View {
22+
if style.showBubbles {
23+
ZStack {
24+
// Number of bubbles
25+
ForEach (1...10, id:\.self) { _ in
26+
Circle()
27+
.foregroundColor(style.bubbleColor.opacity(Double.random(in: 0.15...0.25)))
28+
.scaleEffect(self.scale * .random(in: 0.5...1))
29+
.frame(width: .random(in: 1...25),
30+
height: CGFloat.random (in: 20...25),
31+
alignment: .center)
32+
.position(
33+
CGPoint(
34+
x: .random(in: style.circleSize/4...style.circleSize/1.3),
35+
y: .random (in: style.circleSize/5...style.circleSize/1.2)
36+
)
37+
)
38+
}
39+
}
40+
.task {
41+
withAnimation(
42+
.spring (dampingFraction: 0.5)
43+
.repeatForever()
44+
.speed(.random(in: 0.1...0.15))
45+
.delay(.random(in: 0.01...0.1))
46+
) {
47+
self.scale = 1.2 // default circle scale
48+
}
49+
}
50+
}
51+
}
52+
}
53+
54+
#Preview {
55+
BubbleView()
56+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// CheckmarkView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Rahul Yadav on 15/07/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct CheckmarkView: View {
11+
12+
// MARK: Variables
13+
14+
/// Decide weather to make checkmark visible or not
15+
@State var displayCheckmark: Bool = false
16+
17+
/// Initial Zoom of Checkmark
18+
@State private var zoom = 0.1
19+
20+
/// Style for SSWaterProgress View
21+
var style: SSWaterProgressViewStyle
22+
23+
var body: some View {
24+
checkMarkImg
25+
}
26+
27+
private var checkMarkImg: some View {
28+
Image(systemName: style.checkMarkImg)
29+
.resizable()
30+
.frame(width: style.circleSize/3, height: style.circleSize/3)
31+
.opacity(displayCheckmark ? 1 : 0)
32+
.foregroundStyle(style.checkMarkImgColor)
33+
.scaleEffect(zoom, anchor: .center)
34+
.foregroundColor(.white)
35+
.animation(.spring(dampingFraction: 0.4), value: displayCheckmark)
36+
.onAppear() {
37+
displayCheckmark.toggle()
38+
zoom = 1.0
39+
}
40+
}
41+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// WaterCircleOutlineView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Rahul Yadav on 09/07/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct WaterCircleOutlineView: View {
11+
12+
// MARK: - Variables
13+
14+
/// Outline Progress value
15+
@Binding var progress: Double
16+
17+
/// Used for styling the view
18+
var style: SSWaterProgressViewStyle
19+
20+
var body: some View {
21+
ZStack {
22+
Circle()
23+
.stroke(style.emptyStrokeColor, style: StrokeStyle(lineWidth: style.circleStrokeWidth, lineCap: .round))
24+
.frame(width: style.circleSize,
25+
height: style.circleSize)
26+
Circle()
27+
.trim(from: 0.0, to: CGFloat(progress))
28+
.stroke(style.fillStrokeColor, style: StrokeStyle(lineWidth: style.circleStrokeWidth, lineCap: .round))
29+
.frame(width: style.circleSize, height: style.circleSize)
30+
.rotationEffect(.degrees(-90))
31+
.transition(.slide)
32+
}
33+
}
34+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//
2+
// WaterCircleView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Rahul Yadav on 09/07/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct WaterCircleView: Shape {
11+
12+
// MARK: - Variables
13+
14+
/// Progress Value used to determine the height of water
15+
var progress: Double
16+
17+
/// Initial Animation Start
18+
var offset: Angle
19+
20+
/// Enabling Animation
21+
var animatableData: Double {
22+
get { offset.degrees }
23+
set { offset = Angle(degrees: newValue) }
24+
}
25+
26+
/**
27+
Creates a path that represents a wave or a solid background, depending on the provided progress value.
28+
29+
- Parameters:
30+
- rect: A CGRect object defining the rectangle within which the path will be created.
31+
32+
- Returns:
33+
A Path object representing the wave or solid background.
34+
35+
This function generates a path suitable for drawing a wave or a solid rectangle within the given rectangle. It calculates the wave height and position based on the `progress` value (assumed to be a variable outside the function).
36+
37+
The path creation process involves the following steps:
38+
39+
1. **Wave Parameters:** It defines the lowest and highest possible wave heights (`lowestWave` and `highestWave`).
40+
2. **Wave Height Calculation:** Calculates the normalized wave height (`newPercent`) based on `progress`, and then determines the wave's amplitude (`waveHeight`) and vertical position (`yOffSet`) within the rectangle. The Animation is of Wave style until progress is not 100% else it will be solid background.
41+
3. **Path Creation:**
42+
- **Starting Point:** Sets the starting point on the top of the wave based on `yOffSet` and the initial sine value.
43+
- **Wave Segments:** Iterates through angles to create line segments that represent the wave's shape.
44+
- **Connecting Lines:** Connects the last wave point to the bottom-right corner and then to the bottom-left corner, completing the shape.
45+
- **Closing the Path:** Closes the path by connecting the bottom-left corner back to the starting point.
46+
47+
- Note: This function relies on external variables `progress` and `offset`.
48+
*/
49+
func path(in rect: CGRect) -> Path {
50+
var wavePath = Path()
51+
let lowestWave = 0.02
52+
let highestWave = 1.00
53+
54+
let newPercent = lowestWave + (highestWave - lowestWave) * (progress/100)
55+
56+
let waveHeight = progress == 100 ? 0 : 0.03 * rect.height
57+
let yOffSet = CGFloat(1 - newPercent) *
58+
(rect.height - 4 * waveHeight) + 2 * waveHeight
59+
let startAngle = offset
60+
let endAngle = offset + Angle(degrees: 360 + 10)
61+
62+
wavePath.move(to: CGPoint(x: 0, y: yOffSet + waveHeight *
63+
CGFloat(sin(offset.radians))))
64+
65+
for angle in stride(from: startAngle.degrees, through: endAngle.degrees, by: 5) {
66+
let x = CGFloat((angle - startAngle.degrees) / 360) * rect.width
67+
wavePath.addLine(to: CGPoint(x: x, y: yOffSet + waveHeight * CGFloat(sin(Angle(degrees: angle).radians))))
68+
}
69+
70+
wavePath.addLine(to: CGPoint(x: rect.width, y: rect.height))
71+
wavePath.addLine(to: CGPoint(x: 0, y: rect.height))
72+
wavePath.closeSubpath()
73+
return wavePath
74+
}
75+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// WaterProgressTextView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Rahul Yadav on 16/07/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct WaterProgressTextView: View {
11+
12+
// MARK: - Variable
13+
14+
/// Decide weather to show percentage text or not
15+
var showPercentage: Bool
16+
17+
/// Progress percent value
18+
@Binding var progress: Double
19+
20+
/// For Styling text
21+
var style: SSWaterProgressViewStyle
22+
23+
var body: some View {
24+
if showPercentage {
25+
Text("\(Int(progress * 100))%")
26+
.font(style.progressFont)
27+
.foregroundStyle(style.progressTextColor)
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)