Skip to content

Commit

Permalink
Merge pull request #11 from SimformSolutionsPvtLtd/feature/UNT-T26889…
Browse files Browse the repository at this point in the history
…-Water_effect_animation

UNT-T26889 - Add Water Effect Progress Animation View
  • Loading branch information
bhargavbajani-simformsolutions authored Jul 19, 2024
2 parents c292ca4 + 6afefdf commit f2d8c97
Show file tree
Hide file tree
Showing 10 changed files with 547 additions and 1 deletion.
40 changes: 40 additions & 0 deletions SSSwiftUIAnimations.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
B1DFCA532BF4FC7900F01505 /* ArrowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1DFCA522BF4FC7900F01505 /* ArrowView.swift */; };
B1EA09DE2C11A6B70024BC28 /* Banner.png in Resources */ = {isa = PBXBuildFile; fileRef = B1EA09DD2C11A6B70024BC28 /* Banner.png */; };
B1FE861E2BFF6BC000FB111C /* ViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1FE861D2BFF6BC000FB111C /* ViewExtension.swift */; };
B717EC9D2C45488100555F90 /* CheckmarkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B717EC9C2C45488100555F90 /* CheckmarkView.swift */; };
B741D9A62C46448200ABFCB4 /* WaterProgressTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B741D9A52C46448200ABFCB4 /* WaterProgressTextView.swift */; };
B780A9182C3D063500342512 /* WaterProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9172C3D063500342512 /* WaterProgressView.swift */; };
B780A91A2C3D0BCB00342512 /* WaterProgressViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9192C3D0BCB00342512 /* WaterProgressViewStyle.swift */; };
B780A9242C3D7A7C00342512 /* WaterCircleOutlineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9232C3D7A7C00342512 /* WaterCircleOutlineView.swift */; };
B780A9262C3D806300342512 /* ExampleWaterProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9252C3D806300342512 /* ExampleWaterProgressView.swift */; };
B780A9282C3D851700342512 /* WaterCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B780A9272C3D851700342512 /* WaterCircleView.swift */; };
B7ECD58D2C452D8100B6A703 /* BubbleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7ECD58C2C452D8100B6A703 /* BubbleView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -61,6 +69,14 @@
B1DFCA522BF4FC7900F01505 /* ArrowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowView.swift; sourceTree = "<group>"; };
B1EA09DD2C11A6B70024BC28 /* Banner.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Banner.png; sourceTree = "<group>"; };
B1FE861D2BFF6BC000FB111C /* ViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtension.swift; sourceTree = "<group>"; };
B717EC9C2C45488100555F90 /* CheckmarkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckmarkView.swift; sourceTree = "<group>"; };
B741D9A52C46448200ABFCB4 /* WaterProgressTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterProgressTextView.swift; sourceTree = "<group>"; };
B780A9172C3D063500342512 /* WaterProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterProgressView.swift; sourceTree = "<group>"; };
B780A9192C3D0BCB00342512 /* WaterProgressViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterProgressViewStyle.swift; sourceTree = "<group>"; };
B780A9232C3D7A7C00342512 /* WaterCircleOutlineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterCircleOutlineView.swift; sourceTree = "<group>"; };
B780A9252C3D806300342512 /* ExampleWaterProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleWaterProgressView.swift; sourceTree = "<group>"; };
B780A9272C3D851700342512 /* WaterCircleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterCircleView.swift; sourceTree = "<group>"; };
B7ECD58C2C452D8100B6A703 /* BubbleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -154,6 +170,7 @@
children = (
B19E0B652BF7498700E65974 /* ExampleProgressView.swift */,
B153FD142BFB7A7900AEFE83 /* ExampleLRArrowView.swift */,
B780A9252C3D806300342512 /* ExampleWaterProgressView.swift */,
B1F9ED332BFCD85000189871 /* ExamplesList */,
);
path = Examples;
Expand All @@ -162,6 +179,7 @@
B1DE99D72C060E1A006995FB /* Sources */ = {
isa = PBXGroup;
children = (
B780A9162C3D05CD00342512 /* WaterProgressAnimation */,
B14AB36A2BC40286004B09C4 /* ProgressAnimation */,
469963A3290FCE1900DC01AD /* ArrowLeftRightAnimation */,
);
Expand All @@ -186,6 +204,20 @@
path = ExamplesList;
sourceTree = "<group>";
};
B780A9162C3D05CD00342512 /* WaterProgressAnimation */ = {
isa = PBXGroup;
children = (
B780A9172C3D063500342512 /* WaterProgressView.swift */,
B780A9192C3D0BCB00342512 /* WaterProgressViewStyle.swift */,
B780A9232C3D7A7C00342512 /* WaterCircleOutlineView.swift */,
B780A9272C3D851700342512 /* WaterCircleView.swift */,
B7ECD58C2C452D8100B6A703 /* BubbleView.swift */,
B717EC9C2C45488100555F90 /* CheckmarkView.swift */,
B741D9A52C46448200ABFCB4 /* WaterProgressTextView.swift */,
);
path = WaterProgressAnimation;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -273,10 +305,18 @@
B15FD7992C04785700752CEA /* CustomToolBar.swift in Sources */,
469963A5290FCE3600DC01AD /* SSLRArrowView.swift in Sources */,
B153FD0C2BFB3C1800AEFE83 /* LRArrowAnimStyle.swift in Sources */,
B717EC9D2C45488100555F90 /* CheckmarkView.swift in Sources */,
B780A9282C3D851700342512 /* WaterCircleView.swift in Sources */,
B153FD132BFB71F500AEFE83 /* FilledStrokeCircle.swift in Sources */,
2BC2D8F328CF3A6F00CAB302 /* SSSwiftUIAnimationsApp.swift in Sources */,
B741D9A62C46448200ABFCB4 /* WaterProgressTextView.swift in Sources */,
B780A9242C3D7A7C00342512 /* WaterCircleOutlineView.swift in Sources */,
B1DFCA532BF4FC7900F01505 /* ArrowView.swift in Sources */,
B780A9182C3D063500342512 /* WaterProgressView.swift in Sources */,
B11B983A2BCE9C3F00D76016 /* CheckView.swift in Sources */,
B7ECD58D2C452D8100B6A703 /* BubbleView.swift in Sources */,
B780A9262C3D806300342512 /* ExampleWaterProgressView.swift in Sources */,
B780A91A2C3D0BCB00342512 /* WaterProgressViewStyle.swift in Sources */,
B1DFCA512BF4FA3D00F01505 /* ProgressCircle.swift in Sources */,
B14AB36C2BC41B05004B09C4 /* ProgressView.swift in Sources */,
B1FE861E2BFF6BC000FB111C /* ViewExtension.swift in Sources */,
Expand Down
46 changes: 46 additions & 0 deletions SSSwiftUIAnimations/Examples/ExampleWaterProgressView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// ExampleWaterProgressView.swift
// SSSwiftUIAnimations
//
// Created by Rahul Yadav on 09/07/24.
//

import SwiftUI

struct ExampleWaterProgressView: View {

// MARK: - Variables
@State private var progress: Double = 0.0

var body: some View {
VStack {
SSWaterProgressView(progress: $progress,
showPercent: true,
style: SSWaterProgressViewStyle(
circleSize: 200,
circleStrokeWidth: 10,
progressFont: .system(size: 16, weight: .bold),
progressTextColor: .black,
emptyStrokeColor: .cyan.opacity(0.2),
fillStrokeColor: .cyan,
waterColor: .mint,
showBubbles: true,
bubbleColor: .white,
checkMarkImg: "checkmark",
checkMarkImgColor: .white
),
onProgressCompletion: { print("Progress Completed") })
Spacer()
.frame(height: 40)
Slider(value: $progress) {
Text("Slide to manage progress")
}
.frame(width: 150, alignment: .bottom)
}
.customToolbar(title: "Water ProgressView Example", fontSize: 17)
}
}

#Preview {
ExampleWaterProgressView()
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ class ExampleListModel: Identifiable {
}

// data for example row list
static let exampleList = [ExampleListModel(rowTitle: "ProgressView", destinationView: AnyView(ExampleProgressView())), ExampleListModel(rowTitle: "Arrow Left Right View", destinationView: AnyView(ExampleLRArrowView()))]
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()))]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// BubbleView.swift
// SSSwiftUIAnimations
//
// Created by Rahul Yadav on 15/07/24.
//

import SwiftUI

/// Create a view with Bubbles used in animation
struct BubbleView: View {

// MARK: Variables

/// Used for styling the view
@State var style: SSWaterProgressViewStyle = SSWaterProgressViewStyle()

/// Initial Bubble Scale
@State private var scale : CGFloat = 1

var body: some View {
if style.showBubbles {
ZStack {
// Number of bubbles
ForEach (1...10, id:\.self) { _ in
Circle()
.foregroundColor(style.bubbleColor.opacity(Double.random(in: 0.15...0.25)))
.scaleEffect(self.scale * .random(in: 0.5...1))
.frame(width: .random(in: 1...25),
height: CGFloat.random (in: 20...25),
alignment: .center)
.position(
CGPoint(
x: .random(in: style.circleSize/4...style.circleSize/1.3),
y: .random (in: style.circleSize/5...style.circleSize/1.2)
)
)
}
}
.task {
withAnimation(
.spring (dampingFraction: 0.5)
.repeatForever()
.speed(.random(in: 0.1...0.15))
.delay(.random(in: 0.01...0.1))
) {
self.scale = 1.2 // default circle scale
}
}
}
}
}

#Preview {
BubbleView()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// CheckmarkView.swift
// SSSwiftUIAnimations
//
// Created by Rahul Yadav on 15/07/24.
//

import SwiftUI

struct CheckmarkView: View {

// MARK: Variables

/// Decide weather to make checkmark visible or not
@State var displayCheckmark: Bool = false

/// Initial Zoom of Checkmark
@State private var zoom = 0.1

/// Style for SSWaterProgress View
var style: SSWaterProgressViewStyle

var body: some View {
checkMarkImg
}

private var checkMarkImg: some View {
Image(systemName: style.checkMarkImg)
.resizable()
.frame(width: style.circleSize/3, height: style.circleSize/3)
.opacity(displayCheckmark ? 1 : 0)
.foregroundStyle(style.checkMarkImgColor)
.scaleEffect(zoom, anchor: .center)
.foregroundColor(.white)
.animation(.spring(dampingFraction: 0.4), value: displayCheckmark)
.onAppear() {
displayCheckmark.toggle()
zoom = 1.0
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// WaterCircleOutlineView.swift
// SSSwiftUIAnimations
//
// Created by Rahul Yadav on 09/07/24.
//

import SwiftUI

struct WaterCircleOutlineView: View {

// MARK: - Variables

/// Outline Progress value
@Binding var progress: Double

/// Used for styling the view
var style: SSWaterProgressViewStyle

var body: some View {
ZStack {
Circle()
.stroke(style.emptyStrokeColor, style: StrokeStyle(lineWidth: style.circleStrokeWidth, lineCap: .round))
.frame(width: style.circleSize,
height: style.circleSize)
Circle()
.trim(from: 0.0, to: CGFloat(progress))
.stroke(style.fillStrokeColor, style: StrokeStyle(lineWidth: style.circleStrokeWidth, lineCap: .round))
.frame(width: style.circleSize, height: style.circleSize)
.rotationEffect(.degrees(-90))
.transition(.slide)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// WaterCircleView.swift
// SSSwiftUIAnimations
//
// Created by Rahul Yadav on 09/07/24.
//

import SwiftUI

struct WaterCircleView: Shape {

// MARK: - Variables

/// Progress Value used to determine the height of water
var progress: Double

/// Initial Animation Start
var offset: Angle

/// Enabling Animation
var animatableData: Double {
get { offset.degrees }
set { offset = Angle(degrees: newValue) }
}

/**
Creates a path that represents a wave or a solid background, depending on the provided progress value.
- Parameters:
- rect: A CGRect object defining the rectangle within which the path will be created.
- Returns:
A Path object representing the wave or solid background.
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).
The path creation process involves the following steps:
1. **Wave Parameters:** It defines the lowest and highest possible wave heights (`lowestWave` and `highestWave`).
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.
3. **Path Creation:**
- **Starting Point:** Sets the starting point on the top of the wave based on `yOffSet` and the initial sine value.
- **Wave Segments:** Iterates through angles to create line segments that represent the wave's shape.
- **Connecting Lines:** Connects the last wave point to the bottom-right corner and then to the bottom-left corner, completing the shape.
- **Closing the Path:** Closes the path by connecting the bottom-left corner back to the starting point.
- Note: This function relies on external variables `progress` and `offset`.
*/
func path(in rect: CGRect) -> Path {
var wavePath = Path()
let lowestWave = 0.02
let highestWave = 1.00

let newPercent = lowestWave + (highestWave - lowestWave) * (progress/100)

let waveHeight = progress == 100 ? 0 : 0.03 * rect.height
let yOffSet = CGFloat(1 - newPercent) *
(rect.height - 4 * waveHeight) + 2 * waveHeight
let startAngle = offset
let endAngle = offset + Angle(degrees: 360 + 10)

wavePath.move(to: CGPoint(x: 0, y: yOffSet + waveHeight *
CGFloat(sin(offset.radians))))

for angle in stride(from: startAngle.degrees, through: endAngle.degrees, by: 5) {
let x = CGFloat((angle - startAngle.degrees) / 360) * rect.width
wavePath.addLine(to: CGPoint(x: x, y: yOffSet + waveHeight * CGFloat(sin(Angle(degrees: angle).radians))))
}

wavePath.addLine(to: CGPoint(x: rect.width, y: rect.height))
wavePath.addLine(to: CGPoint(x: 0, y: rect.height))
wavePath.closeSubpath()
return wavePath
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// WaterProgressTextView.swift
// SSSwiftUIAnimations
//
// Created by Rahul Yadav on 16/07/24.
//

import SwiftUI

struct WaterProgressTextView: View {

// MARK: - Variable

/// Decide weather to show percentage text or not
var showPercentage: Bool

/// Progress percent value
@Binding var progress: Double

/// For Styling text
var style: SSWaterProgressViewStyle

var body: some View {
if showPercentage {
Text("\(Int(progress * 100))%")
.font(style.progressFont)
.foregroundStyle(style.progressTextColor)
}
}
}
Loading

0 comments on commit f2d8c97

Please sign in to comment.