30 Days of SwiftUI - Day 17: The Art of Motion: Mastering Animations in SwiftUI


Hello Swift animators! Today, we're diving deep into the world of SwiftUI animations. We'll explore implicit and explicit animations, gestures, transitions, and even create custom animations. Let's get moving!

The Magic of Motion: Introduction to SwiftUI Animations

SwiftUI makes animations incredibly easy and intuitive. With just a few lines of code, you can bring your UI to life.

Effortless Motion: Creating Implicit Animations

Implicit animations are triggered automatically when a view's state changes.

Example: Simple Implicit Animation

import SwiftUI

struct ImplicitAnimation: View {
    @State private var isScaled = false

    var body: some View {
        Circle()
            .fill(Color.blue)
            .scaleEffect(isScaled ? 1.5 : 1)
            .animation(.easeInOut(duration: 1), value: isScaled)
            .onTapGesture {
                isScaled.toggle()
            }
    }
}

struct ImplicitAnimation_Previews: PreviewProvider {
    static var previews: some View {
        ImplicitAnimation()
    }
}

Visual Representation:

  • A blue circle smoothly scales up and down when tapped.

  • .scaleEffect(): Changes the size of the circle.

  • .animation(.easeInOut(duration: 1), value: isScaled): Animates the scale change with an ease-in-out curve over 1 second.

Fine-Tuning Motion: Customizing Animations in SwiftUI

SwiftUI provides various animation curves and durations to customize your animations.

Example: Custom Animation Curves

import SwiftUI

struct CustomAnimation: View {
    @State private var rotation = 0.0

    var body: some View {
        Rectangle()
            .fill(Color.red)
            .frame(width: 100, height: 100)
            .rotationEffect(.degrees(rotation))
            .animation(.spring(response: 1, dampingFraction: 0.5), value: rotation)
            .onTapGesture {
                rotation += 90
            }
    }
}

struct CustomAnimation_Previews: PreviewProvider {
    static var previews: some View {
        CustomAnimation()
    }
}

Visual Representation:

  • A red rectangle smoothly rotates when tapped, with a spring-like animation.

  • .spring(response:dampingFraction:): Uses a spring animation effect.

Dynamic Data: Animating Bindings

You can animate changes to bound values, creating dynamic and responsive animations.

Example: Animating Binding Changes

import SwiftUI

struct BindingAnimation: View {
    @State private var sliderValue = 0.0

    var body: some View {
        VStack {
            Slider(value: $sliderValue)
                .padding()

            Rectangle()
                .fill(Color.green)
                .frame(width: CGFloat(sliderValue * 200), height: 50)
                .animation(.linear(duration: 0.5), value: sliderValue)
        }
    }
}

struct BindingAnimation_Previews: PreviewProvider {
    static var previews: some View {
        BindingAnimation()
    }
}

Visual Representation:

  • A green rectangle smoothly changes its width as the slider is moved.

Precise Control: Creating Explicit Animations

Explicit animations give you more control over when and how animations occur.

Example: Explicit Animation with withAnimation

import SwiftUI

struct ExplicitAnimation: View {
    @State private var isTapped = false

    var body: some View {
        Button("Animate") {
            withAnimation(.easeInOut(duration: 1)) {
                isTapped.toggle()
            }
        }
        .padding()
        .background(isTapped ? Color.orange : Color.blue)
        .foregroundColor(.white)
        .cornerRadius(10)
    }
}

struct ExplicitAnimation_Previews: PreviewProvider {
    static var previews: some View {
        ExplicitAnimation()
    }
}

Visual Representation:

  • The button's background color smoothly transitions between orange and blue when tapped.

  • withAnimation: Explicitly triggers the animation.

Orchestrating Motion: Controlling the Animation Stack

SwiftUI's animation stack allows you to chain animations together.

Example: Chained Animations

import SwiftUI

struct ChainedAnimation: View {
    @State private var scale = 1.0
    @State private var opacity = 1.0

    var body: some View {
        Circle()
            .fill(Color.purple)
            .scaleEffect(scale)
            .opacity(opacity)
            .onTapGesture {
                withAnimation(.easeInOut(duration: 1)) {
                    scale = 1.5
                }
                withAnimation(.easeInOut(duration: 1).delay(1)) {
                    opacity = 0.5
                }
            }
    }
}

struct ChainedAnimation_Previews: PreviewProvider {
    static var previews: some View {
        ChainedAnimation()
    }
}

Visual Representation:

  • A purple circle scales up, then its opacity fades after a delay.

Interactive Motion: Animating Gestures

You can animate views in response to user gestures.

Example: Gesture-Driven Animation

import SwiftUI

struct GestureAnimation: View {
    @State private var dragOffset = CGSize.zero

    var body: some View {
        Circle()
            .fill(Color.yellow)
            .frame(width: 100, height: 100)
            .offset(dragOffset)
            .gesture(
                DragGesture()
                    .onChanged { value in
                        dragOffset = value.translation
                    }
                    .onEnded { _ in
                        withAnimation(.spring()) {
                            dragOffset = .zero
                        }
                    }
            )
    }
}

struct GestureAnimation_Previews: PreviewProvider {
    static var previews: some View {
        GestureAnimation()
    }
}

Visual Representation:

  • A yellow circle moves with the drag gesture and smoothly returns to its original position.

Appear and Disappear: Showing and Hiding Views with Transitions

Transitions provide smooth animations for showing and hiding views.

Example: View Transition

import SwiftUI

struct TransitionAnimation: View {
    @State private var showDetails = false

    var body: some View {
        VStack {
            Button("Toggle Details") {
                withAnimation {
                    showDetails.toggle()
                }
            }
            if showDetails {
                Text("Detailed Information")
                    .transition(.scale)
            }
        }
    }
}

struct TransitionAnimation_Previews: PreviewProvider {
    static var previews: some View {
        TransitionAnimation()
    }
}

Visual Representation:

  • "Detailed Information" text smoothly scales in and out when the button is tapped.

Crafted Transitions: Building Custom Transitions Using ViewModifier

You can create custom transitions using ViewModifier to achieve unique animation effects.

Example (simplified):

import SwiftUI

struct CustomTransition: ViewModifier {
    let opacity: Double

    func body(content: Content) -> some View {
        content.opacity(opacity)
    }
}

extension AnyTransition {
    static var fade: AnyTransition {
        .modifier(active: CustomTransition(opacity: 0), identity: CustomTransition(opacity: 1))
    }
}

struct CustomTransitionView: View {
    @State private var showText = false

    var body: some View {
        VStack {
            Button("Toggle Text") {
                withAnimation {
                    showText.toggle()
                }
            }
            if showText {
                Text("Custom Fade")
                    .transition(.fade)
            }
        }
    }
}

struct CustomTransitionView_Previews: PreviewProvider {
    static var previews: some View {
        CustomTransitionView()
    }
}

Visual Representation:

  • "Custom Fade" text fades in and out.

🔥 Conclusion

Day 17 has been a whirlwind of animation exploration. From implicit and explicit animations to gestures and custom transitions, you've learned to bring your SwiftUI interfaces to life. Keep experimenting, and you'll be creating stunning animated experiences!


Follow me on Linkedin: igatitech 🚀🚀🚀

Comments

Popular posts from this blog

30 Days of SwiftUI — Day 1: Getting Started with SwiftUI

30 Days of SwiftUI Learning Journey: From Zero to Hero!

30 Days of SwiftUI - Day 11: Building Interactive SwiftUI Apps