Video yükleniyor...
Video Yüklenemedi
I've started meditating again after a while. 🧘🏼 So, naturally, I wanted to copy the Headspace app's loading animation. I spent way too much time rebuilding it using #SwiftUI. I tried improving it (original in comment), let me know Headspace if you need access to the code.😇
93,359 görüntüleme • 1 yıl önce •via X (Twitter)
36 Yorum

Here's the original animation:

Make code reviews seamless with Qodo Merge. Directly implement changes to PRs, apply modifications from review comments, and fine-tune updates using intelligent suggestions. Let Qodo Merge learn and adapt to your team’s best practices for better results.

Had a go at the animation part, here's my effort: import SwiftUI struct ContentView: View { @State private var scale: CGFloat = 0.1 @State private var yOffset: CGFloat = 0 @State private var breatheIn = false @State private var animationStarted = false var body: some View { GeometryReader { geometry in ZStack { Color(UIColor.systemIndigo).ignoresSafeArea() ZStack { Circle() .fill( .frame(width: geometry.size.width * 0.8, height: geometry.size.width * 0.8) .scaleEffect(scale * (breatheIn ? 1.6 : 1.1)) FaceView(breatheIn: breatheIn) .frame(width: geometry.size.width * 0.4, height: geometry.size.width * 0.4) .offset(y: -geometry.size.height * 0.3) .scaleEffect(scale * (breatheIn ? 0.8 : 0.6)) } .offset(y: yOffset + (breatheIn ? -geometry.size.height * 0.1 : 0)) } .onAppear { withAnimation(.easeInOut(duration: 2)) { scale = 1.5 yOffset = geometry.size.height * 0.45 } DispatchQueue.main.asyncAfter(deadline: .now() + 2) { animationStarted = true withAnimation(Animation.easeInOut(duration: 4).repeatForever(autoreverses: true)) { breatheIn.toggle() } } } } } } struct FaceView: View { var breatheIn: Bool let strokeWidth: CGFloat = 0.08 var body: some View { GeometryReader { geometry in ZStack { // Eyes EyeView() .stroke( style: StrokeStyle(lineWidth: geometry.size.width * strokeWidth, lineCap: .round, lineJoin: .round)) .frame(width: geometry.size.width, height: geometry.size.height * 0.4) .position(x: geometry.size.width / 2, y: geometry.size.height * 0.4) // Smile SmileShape(progress: breatheIn ? 1 : 0) .stroke( style: StrokeStyle(lineWidth: geometry.size.width * strokeWidth, lineCap: .round, lineJoin: .round)) .frame(width: geometry.size.width, height: geometry.size.height * 0.6) .position(x: geometry.size.width / 2, y: geometry.size.height * 0.7) .animation(.easeInOut(duration: 4).repeatForever(autoreverses: true), value: breatheIn) } } } } struct EyeView: Shape { func path(in rect: CGRect) -> Path { var path = Path() let width = rect.width let height = rect.height // Left eye path.move(to: CGPoint(x: width * 0.2, y: height * 0.5)) path.addQuadCurve( to: CGPoint(x: width * 0.4, y: height * 0.5), control: CGPoint(x: width * 0.3, y: height * 0.3) ) // Right eye path.move(to: CGPoint(x: width * 0.6, y: height * 0.5)) path.addQuadCurve( to: CGPoint(x: width * 0.8, y: height * 0.5), control: CGPoint(x: width * 0.7, y: height * 0.3) ) return path } } struct SmileShape: Shape { var progress: CGFloat var animatableData: CGFloat { get { progress } set { progress = newValue } } func path(in rect: CGRect) -> Path { var path = Path() let width = rect.width let height = rect.height let smileWidth = 0.4 + (0.6 * progress) let smileHeight = 0.55 + (0.55 * progress) let startX = width * ((1 - smileWidth) / 2) let endX = width * (1 - (1 - smileWidth) / 2) path.move(to: CGPoint(x: startX, y: height * 0.6)) path.addQuadCurve( to: CGPoint(x: endX, y: height * 0.6), control: CGPoint(x: width * 0.5, y: height * smileHeight) ) return path } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

@Headspace Wow thats pretty neat!

@Headspace Thanks a lot. Really enjoyed building out that one.

@Headspace Looking very good though! Nice work!

@Headspace Thank you, Simon!

@Headspace I sometimes wonder how I can do this on the web.

@Headspace That is an excellent question. In my experience, keyframe animations can get you quite far: But for these more complex ones, I have achieved great results with @framer motion:

@Headspace Looks amazing! Not Headspace but wud love access to the code 😅

@Headspace Did you use Xcode 16 yet? Curious whether those AI features did any good to your project!

@Headspace I did use Xcode 16, but not any of the AI features. I'm not sure why the Autocomplete doesn't work for me yet. Maybe I missed activating it at some point. 😇 But to answer your question, there was no AI help for this one.

@Headspace really good! I just felt the breathing is a bit too fast, but maybe it's the video speed. great stuff!

@Headspace Thank you! Yes, you might be right. It could indeed be a bit slower. The problem is that you're never finished with an animation like this. So, at some point, I just needed to say, "It's good enough," and at least share it. But good catch!

@Headspace 👏👏👏👏👏

@Headspace That animation looks awesome! Did rebuilding it in SwiftUI end up being more relaxing than meditating? 😄

@startdustdev @Headspace Haha, thank you. And the creation of the animation was not more relaxing than a meditation. However, I can get into a very focused state while working on things like that, which probably has a therapeutic effect to some degree. :)

I would love to see the code, pls

@Headspace That's awesome, Stefan! Your dedication to meditating and then taking the time to rebuild the animation in SwiftUI is really inspiring. Would love to see more of your creative projects!

@Headspace Thank you! I will share more of the experiments I'm building and even plan to turn some of them into tutorials to share the techniques used for others to learn. :)

@Headspace It looks great Stefan

@Headspace Thanks Khoa, I definitely went the extra mile here. But it was just so much fun. :)

@Headspace Genial !

@Headspace Great animation 🔥

@Headspace I'm not headspace but I need the code 😀

@Headspace Looks Awesome!

@Headspace Nice 🤩

@Headspace Wow! This is awesome!

@Headspace Where is the link to your SwiftUI course? 😂😂

@Headspace Please share the code to let usl learning the animation thank you

@Headspace Looks Amazing @stefanjblos ... How can I do it in Android...

@Headspace Wonder if I could replicate it using react native reanimated 🤔

@Headspace Smoothhhh! 🔥

@Headspace Wow this is really nice. If I was one of the users, I’d create that account. Also thank you for sharing the code

@Headspace looks really nice!

@Headspace Love the animation
