Created
January 24, 2024 11:22
-
-
Save MoussaHellal/cc374eb61c76875813414cfb6554aca7 to your computer and use it in GitHub Desktop.
Provides a Wave Animation
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
import SwiftUI | |
struct ContentView: View { | |
/// The percentage value controlling the wave animation. | |
@State private var percent: CGFloat = 60.0 | |
/// The linear gradient defining the color of the wave. | |
@State private var color = LinearGradient(colors: [.cyan, .cyan.opacity(0.5)], startPoint: .top, endPoint: .bottom) | |
var body: some View { | |
VStack { | |
CircleWaveView(percent: 50, color: LinearGradient(colors: [.cyan, .cyan.opacity(0.5)], startPoint: .top, endPoint: .bottom)) | |
CircleWaveView(percent: 75, color: LinearGradient(colors: [.red, .yellow , .cyan.opacity(0.5)], startPoint: .top, endPoint: .bottom)) | |
CircleWaveView(percent: 75, color: LinearGradient(colors: [.cyan, .blue.opacity(0.5)], startPoint: .top, endPoint: .bottom)) | |
CircleWaveView(percent: 50, color: LinearGradient(colors: [.blue, .blue.opacity(0.7)], startPoint: .top, endPoint: .bottom)) | |
} | |
.frame(maxWidth: .infinity, maxHeight: .infinity) | |
.background(.white) | |
} | |
} | |
struct ContentView_Previews: PreviewProvider { | |
static var previews: some View { | |
VStack { | |
CircleWaveView(percent: 58, color: LinearGradient(colors: [.cyan, .cyan.opacity(0.5)], startPoint: .top, endPoint: .bottom)) | |
CircleWaveView(percent: 80, color: LinearGradient(colors: [.red, .white,.cyan.opacity(0.5)], startPoint: .top, endPoint: .bottom)) | |
CircleWaveView(percent: 30, color: LinearGradient(colors: [.cyan, .blue.opacity(0.5)], startPoint: .top, endPoint: .bottom)) | |
} | |
.background(.gray.opacity(0.2)) | |
.frame(maxHeight: .infinity) | |
} | |
} | |
/// A custom shape representing a wave. | |
struct Wave: Shape { | |
/// The angle offset for the wave animation. | |
var offset: Angle | |
/// The percentage value controlling the shape of the wave. | |
var percent: Double | |
/// The animatable data for the wave animation. | |
var animatableData: Double { | |
get { offset.degrees } | |
set { offset = Angle(degrees: newValue) } | |
} | |
/// Creates a path for the wave shape within the specified rectangle. | |
func path(in rect: CGRect) -> Path { | |
var path = Path() | |
let lowestWave = 0.02 | |
let highestWave = 0.98 | |
let newPercent = lowestWave + (highestWave - lowestWave) * percent | |
let waveHeight = 0.015 * rect.height | |
let yoffset = CGFloat(1 - newPercent) * (rect.height - 4 * waveHeight) + 2 * waveHeight | |
let startAngle = offset | |
let endAngle = offset + Angle(degrees: 360) | |
path.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 | |
path.addLine(to: CGPoint(x: x, y: yoffset + waveHeight * CGFloat(sin(Angle(degrees: angle).radians)))) | |
} | |
path.addLine(to: CGPoint(x: rect.width, y: rect.height)) | |
path.addLine(to: CGPoint(x: 0, y: rect.height)) | |
path.closeSubpath() | |
return path | |
} | |
} | |
/// A SwiftUI view displaying a circular wave animation. | |
struct CircleWaveView: View { | |
/// The angle offset for the wave animation. | |
@State private var waveOffset = Angle(degrees: 0) | |
/// The percentage value controlling the shape of the wave. | |
let percent: CGFloat | |
/// The linear gradient defining the color of the wave. | |
let color: LinearGradient | |
var body: some View { | |
GeometryReader { geo in | |
ZStack { | |
Circle() | |
.overlay( | |
Wave(offset: Angle(degrees: self.waveOffset.degrees), percent: Double(percent)/100) | |
.fill(color) | |
.clipShape(Circle().scale(0.92)) | |
) | |
.background(.white) | |
} | |
} | |
.aspectRatio(1, contentMode: .fit) | |
.onAppear { | |
withAnimation(Animation.linear(duration: 2).repeatForever(autoreverses: false)) { | |
self.waveOffset = Angle(degrees: 360) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment