Skip to content

Commit f0bb0be

Browse files
Merge pull request #6 from SimformSolutionsPvtLtd/feature/UNT-T11872-progress-animation
UNT-T11872 Progress view animation
2 parents 3c9f828 + 3b12bc3 commit f0bb0be

File tree

13 files changed

+901
-2
lines changed

13 files changed

+901
-2
lines changed

SSSwiftUIAnimations/SSSwiftUIAnimations.xcodeproj/project.pbxproj

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@
1111
2BC2D8F528CF3A6F00CAB302 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BC2D8F428CF3A6F00CAB302 /* ContentView.swift */; };
1212
2BC2D8F728CF3A7000CAB302 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2BC2D8F628CF3A7000CAB302 /* Assets.xcassets */; };
1313
2BC2D8FA28CF3A7000CAB302 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2BC2D8F928CF3A7000CAB302 /* Preview Assets.xcassets */; };
14+
B10677FE2BE8D0D400957B4E /* DownArrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B10677FD2BE8D0D400957B4E /* DownArrow.swift */; };
15+
B1098E7D2BD94ED900BC19DD /* WaveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1098E7C2BD94ED900BC19DD /* WaveView.swift */; };
16+
B11B983A2BCE9C3F00D76016 /* CheckView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B11B98392BCE9C3F00D76016 /* CheckView.swift */; };
17+
B14AB36C2BC41B05004B09C4 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14AB36B2BC41B05004B09C4 /* ProgressView.swift */; };
18+
B153FD0E2BFB566000AEFE83 /* ExampleListRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B153FD0D2BFB566000AEFE83 /* ExampleListRow.swift */; };
19+
B153FD102BFB649300AEFE83 /* ExampleListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B153FD0F2BFB649300AEFE83 /* ExampleListModel.swift */; };
20+
B177713F2BF39A60001723EC /* ModelClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B177713E2BF39A60001723EC /* ModelClass.swift */; };
21+
B19E0B662BF7498700E65974 /* ExampleProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B19E0B652BF7498700E65974 /* ExampleProgressView.swift */; };
22+
B1DFCA512BF4FA3D00F01505 /* ProgressCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DFCA502BF4FA3D00F01505 /* ProgressCircle.swift */; };
23+
B1DFCA532BF4FC7900F01505 /* ArrowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DFCA522BF4FC7900F01505 /* ArrowView.swift */; };
24+
B1FE861E2BFF6BC000FB111C /* ViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FE861D2BFF6BC000FB111C /* ViewExtension.swift */; };
1425
/* End PBXBuildFile section */
1526

1627
/* Begin PBXFileReference section */
@@ -19,6 +30,17 @@
1930
2BC2D8F428CF3A6F00CAB302 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
2031
2BC2D8F628CF3A7000CAB302 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2132
2BC2D8F928CF3A7000CAB302 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
33+
B10677FD2BE8D0D400957B4E /* DownArrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownArrow.swift; sourceTree = "<group>"; };
34+
B1098E7C2BD94ED900BC19DD /* WaveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaveView.swift; sourceTree = "<group>"; };
35+
B11B98392BCE9C3F00D76016 /* CheckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckView.swift; sourceTree = "<group>"; };
36+
B14AB36B2BC41B05004B09C4 /* ProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = "<group>"; };
37+
B153FD0D2BFB566000AEFE83 /* ExampleListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleListRow.swift; sourceTree = "<group>"; };
38+
B153FD0F2BFB649300AEFE83 /* ExampleListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleListModel.swift; sourceTree = "<group>"; };
39+
B177713E2BF39A60001723EC /* ModelClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelClass.swift; sourceTree = "<group>"; };
40+
B19E0B652BF7498700E65974 /* ExampleProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleProgressView.swift; sourceTree = "<group>"; };
41+
B1DFCA502BF4FA3D00F01505 /* ProgressCircle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressCircle.swift; sourceTree = "<group>"; };
42+
B1DFCA522BF4FC7900F01505 /* ArrowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowView.swift; sourceTree = "<group>"; };
43+
B1FE861D2BFF6BC000FB111C /* ViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtension.swift; sourceTree = "<group>"; };
2244
/* End PBXFileReference section */
2345

2446
/* Begin PBXFrameworksBuildPhase section */
@@ -51,6 +73,8 @@
5173
2BC2D8F128CF3A6F00CAB302 /* SSSwiftUIAnimations */ = {
5274
isa = PBXGroup;
5375
children = (
76+
B14AB36A2BC40286004B09C4 /* ProgressAnimation */,
77+
B153FD112BFB64BE00AEFE83 /* Examples */,
5478
2BC2D8F228CF3A6F00CAB302 /* SSSwiftUIAnimationsApp.swift */,
5579
2BC2D8F428CF3A6F00CAB302 /* ContentView.swift */,
5680
2BC2D8F628CF3A7000CAB302 /* Assets.xcassets */,
@@ -67,6 +91,39 @@
6791
path = "Preview Content";
6892
sourceTree = "<group>";
6993
};
94+
B14AB36A2BC40286004B09C4 /* ProgressAnimation */ = {
95+
isa = PBXGroup;
96+
children = (
97+
B14AB36B2BC41B05004B09C4 /* ProgressView.swift */,
98+
B1DFCA502BF4FA3D00F01505 /* ProgressCircle.swift */,
99+
B1DFCA522BF4FC7900F01505 /* ArrowView.swift */,
100+
B10677FD2BE8D0D400957B4E /* DownArrow.swift */,
101+
B1098E7C2BD94ED900BC19DD /* WaveView.swift */,
102+
B11B98392BCE9C3F00D76016 /* CheckView.swift */,
103+
B177713E2BF39A60001723EC /* ModelClass.swift */,
104+
B1FE861D2BFF6BC000FB111C /* ViewExtension.swift */,
105+
);
106+
path = ProgressAnimation;
107+
sourceTree = "<group>";
108+
};
109+
B153FD112BFB64BE00AEFE83 /* Examples */ = {
110+
isa = PBXGroup;
111+
children = (
112+
B19E0B652BF7498700E65974 /* ExampleProgressView.swift */,
113+
B1F9ED332BFCD85000189871 /* ExamplesList */,
114+
);
115+
path = Examples;
116+
sourceTree = "<group>";
117+
};
118+
B1F9ED332BFCD85000189871 /* ExamplesList */ = {
119+
isa = PBXGroup;
120+
children = (
121+
B153FD0F2BFB649300AEFE83 /* ExampleListModel.swift */,
122+
B153FD0D2BFB566000AEFE83 /* ExampleListRow.swift */,
123+
);
124+
path = ExamplesList;
125+
sourceTree = "<group>";
126+
};
70127
/* End PBXGroup section */
71128

72129
/* Begin PBXNativeTarget section */
@@ -137,8 +194,19 @@
137194
isa = PBXSourcesBuildPhase;
138195
buildActionMask = 2147483647;
139196
files = (
197+
B153FD0E2BFB566000AEFE83 /* ExampleListRow.swift in Sources */,
140198
2BC2D8F528CF3A6F00CAB302 /* ContentView.swift in Sources */,
199+
B153FD102BFB649300AEFE83 /* ExampleListModel.swift in Sources */,
200+
B177713F2BF39A60001723EC /* ModelClass.swift in Sources */,
201+
B10677FE2BE8D0D400957B4E /* DownArrow.swift in Sources */,
202+
B1098E7D2BD94ED900BC19DD /* WaveView.swift in Sources */,
203+
B19E0B662BF7498700E65974 /* ExampleProgressView.swift in Sources */,
141204
2BC2D8F328CF3A6F00CAB302 /* SSSwiftUIAnimationsApp.swift in Sources */,
205+
B1DFCA532BF4FC7900F01505 /* ArrowView.swift in Sources */,
206+
B11B983A2BCE9C3F00D76016 /* CheckView.swift in Sources */,
207+
B1DFCA512BF4FA3D00F01505 /* ProgressCircle.swift in Sources */,
208+
B14AB36C2BC41B05004B09C4 /* ProgressView.swift in Sources */,
209+
B1FE861E2BFF6BC000FB111C /* ViewExtension.swift in Sources */,
142210
);
143211
runOnlyForDeploymentPostprocessing = 0;
144212
};

SSSwiftUIAnimations/SSSwiftUIAnimations/ContentView.swift

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,26 @@
88
import SwiftUI
99

1010
struct ContentView: View {
11+
private var exampleList = ExampleListModel.exampleList
12+
1113
var body: some View {
12-
Text("Hello, world!")
13-
.padding()
14+
NavigationView {
15+
ZStack {
16+
List{
17+
ForEach(exampleList) {item in
18+
ExampleListRow(exampleListItem: item)
19+
}
20+
}.listStyle(.insetGrouped)
21+
.listRowSpacing(10)
22+
.listRowSeparator(.hidden)
23+
.navigationBarTitleDisplayMode(.inline)
24+
.toolbar {
25+
ToolbarItem(placement: .principal) {
26+
Text("Examples").font(Font.system(size: 30, weight: .bold)).foregroundStyle(Color.indigo)
27+
}
28+
}
29+
}
30+
}
1431
}
1532
}
1633

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// ExampleProgressView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Mansi Prajapati on 17/05/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct ExampleProgressView: View {
11+
12+
// MARK: - Variables
13+
@State private var progress: Float = 0.0
14+
@State var timer: Timer?
15+
16+
var body: some View {
17+
VStack {
18+
SSProgressView(progress: $progress, style: SSProgressViewStyle(circleSize: 200, circleStrokeWidth: 5, arrowStrokeWidth: 5, progressTextColor: .pink, fillStrokeColor: .blue, arrowColor: .blue, allowCancelProgress: true), onProgressViewClick: {
19+
simulateDownloadProgress()
20+
}, onProgressCompletion: {
21+
timer?.invalidate()
22+
}, onCancelProgress: {
23+
timer?.invalidate()
24+
})
25+
}.navigationBarTitle("ProgressView Example", displayMode: .inline)
26+
}
27+
28+
// MARK: - Private functions
29+
private func simulateDownloadProgress() {
30+
timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { timer in
31+
if progress >= 1.0 {
32+
timer.invalidate()
33+
} else {
34+
progress += 0.01
35+
}
36+
}
37+
}
38+
}
39+
40+
#Preview {
41+
ExampleProgressView()
42+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// ExampleListModel.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Mansi Prajapati on 20/05/24.
6+
//
7+
8+
import SwiftUI
9+
10+
class ExampleListModel: Identifiable {
11+
12+
// MARK: - Variables
13+
var id = UUID()
14+
var rowTitle: String
15+
var destinationView: AnyView
16+
17+
// MARK: - init
18+
init(rowTitle: String, destinationView: AnyView) {
19+
self.rowTitle = rowTitle
20+
self.destinationView = destinationView
21+
}
22+
23+
// data for example row list
24+
static let exampleList = [ExampleListModel(rowTitle: "ProgressView", destinationView: AnyView(ExampleProgressView()))]
25+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// ExampleListRow.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Mansi Prajapati on 20/05/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct ExampleListRow: View {
11+
var exampleListItem: ExampleListModel
12+
13+
var body: some View {
14+
NavigationLink(destination: exampleListItem.destinationView) {
15+
Text(exampleListItem.rowTitle)
16+
.font(Font.system(size: 16, weight: .bold))
17+
.foregroundStyle(.indigo)
18+
}.listRowBackground(
19+
Capsule()
20+
.fill(
21+
LinearGradient(
22+
gradient: Gradient(colors: [Color.mint, Color.pink]),
23+
startPoint: .topLeading,
24+
endPoint: .bottomTrailing)
25+
)
26+
.padding(.vertical, 2).padding(.horizontal, 0)
27+
)
28+
}
29+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// ArrowView.swift
3+
// SSSwiftUIAnimations
4+
//
5+
// Created by Mansi Prajapati on 15/05/24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct Arrow: View {
11+
12+
// MARK: - Variables
13+
var arrowStyle: ArrowViewParams
14+
var style: SSProgressViewStyle
15+
@Binding var progress: Float
16+
@Binding var bounceEffect: CGFloat
17+
@State var verticalLine = true
18+
19+
var body: some View {
20+
VStack(spacing: 0) {
21+
22+
// Vertical line of arrow
23+
RoundedRectangle(cornerRadius: style.circleStrokeWidth/2)
24+
.frame(
25+
width: arrowStyle.isAnimating ? style.circleStrokeWidth : style.arrowStrokeWidth + 1,
26+
height: arrowStyle.isAnimating ? (!arrowStyle.animationStarted ? style.circleStrokeWidth : style.circleStrokeWidth ) : style.circleSize * 0.40
27+
).opacity((progress >= 0.001) ? 0 : 1)
28+
.foregroundColor(arrowStyle.isAnimating ? style.fillStrokeColor : style.arrowColor)
29+
.offset(y: arrowStyle.isAnimating ? (!arrowStyle.animationStarted ? -10 : -(style.circleSize/2)) : 0)
30+
31+
if progress <= 0.0 {
32+
33+
// if progress is less than 0.1 then showing down arrow animation
34+
DownArrow(
35+
initialAnim: arrowStyle.initialAnim,
36+
isDownward: arrowStyle.isDownward,
37+
progress: Float(progress),
38+
circleSize: style.circleSize,
39+
isAnimating: arrowStyle.isAnimating, bounceEffect: bounceEffect
40+
)
41+
.stroke(style: StrokeStyle(lineWidth: style.arrowStrokeWidth, lineCap: .round))
42+
.frame(width: 10, height: 50)
43+
.padding(.top, -50)
44+
.offset(y: arrowStyle.isAnimating ? 22 : .zero)
45+
.foregroundColor(style.arrowColor)
46+
.scaleEffect(CGSize(width: 1, height: arrowStyle.isAnimating ? 1 : style.circleSize * 0.005))
47+
} else if progress > 0.0 && progress < 1.0 {
48+
49+
// if progress is between >= 0.1 and < 1.0 starting wave animation
50+
WaveView(
51+
progress: $progress,
52+
arrowStrokeWidth: style.arrowStrokeWidth,
53+
width: style.circleSize
54+
)
55+
.frame(width: 10, height: 30)
56+
.foregroundColor(style.arrowColor)
57+
} else if progress >= 1.0 {
58+
59+
// if progress completed showing check mark
60+
CheckView(
61+
width: style.circleSize,
62+
arrowStrokeWidth: style.arrowStrokeWidth
63+
)
64+
.padding(.top, -11)
65+
.offset(y: 22)
66+
.foregroundColor(style.arrowColor)
67+
}
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)