hi I would like to achieve this kind of UI
however so far I only manage to make it looks like this
here is my full code where I have tried to achieve this
struct Wave: Shape {
var animatableData: Double {
get { phase }
set { self.phase = newValue }
}
var strength: Double
var frequency: Double
var phase: Double
var curveAmount: Double
func path(in rect: CGRect) -> Path {
var path = Path()
let width = Double(rect.width)
let height = Double(rect.height)
let midWidth = width / 2
let midHeight = height / 2
let start = CGPoint(x: rect.minX, y: midHeight)
let end = CGPoint(x: rect.maxX, y: midHeight)
let control = CGPoint(x: midWidth, y: rect.minY + strength * curveAmount)
path.move(to: start)
for x in stride(from: 0, through: width, by: 1) {
let progress = x / width
let parabolicY = QuadBezier(t: progress, start: start.y, c: control.y, end: end.y)
let sineWave = sin(progress * frequency * 2 * .pi + phase) * (strength * 0.5)
let y = parabolicY + sineWave
path.addLine(to: CGPoint(x: x, y: y))
}
return path
}
private func QuadBezier(t: Double, start: CGFloat, c: CGFloat, end: CGFloat) -> Double {
let invT = 1 - t
let b1 = 3 * t * (invT * invT)
let b2 = 3 * (t * t) * invT
let b3 = t * t * t
let part1 = Double(start) * Double(invT * invT * invT)
let part2 = Double(c) * Double(b1 + b2)
let part3 = Double(end) * Double(b3)
return part1 + part2 + part3
}
}
struct ContentView: View {
@State private var phase = 0.0
var body: some View {
ZStack {
ForEach(0..<20) { i in
Wave(strength: 10, frequency: 4, phase: self.phase, curveAmount: 30)
.stroke(Color.white.opacity(Double(i) / 10), lineWidth: 5)
.offset(y: CGFloat(i) * 1.2)
}
Wave(strength: 10, frequency: 0, phase: 0, curveAmount: 30)
.stroke(Color.white, lineWidth: 5)
.offset(y: 7 * 5)
}
.background(Color.blue)
.edgesIgnoringSafeArea(.all)
.onAppear {
withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: false)) {
self.phase = .pi * 2
}
}
}
}
does any one know how I can achieve this exact UI?
having hard time to achieve this






