admaDIC App Development & IT Solutions

SwiftUI Animation

by Annett Schwarze | 2025-03-30

Basic Animations in SwiftUI can easily be created using state variables and adjusting them within withAnimation blocks. In this example a view's offset is controlled using a drag gesture. When dragging exceeds a threshold, a new animation is started.

        
import SwiftUI

struct SampleAnimationView: View {
    @State var taskQuestion: String = "1 + 1"
    @State var taskIndex: Int = 1

    @State var taskDragActive: Bool = false
    @State var taskDragEndDone: Bool = false
    let actionThreshold: CGFloat = -100.0
    @State var actionValue: CGFloat = 0.0
    @State var opacityValue: CGFloat = 1.0
    @State var offsetValue: CGFloat = 0.0

    var body: some View {
        VStack(spacing: 0) {
            VStack {
                HStack {
                    Text(taskQuestion)
                        .frame(maxWidth: .infinity)
                }
                .font(.system(size: 40))
                .opacity(opacityValue)
                .offset(x: offsetValue, y: 0)
            }
            .padding(5)
            .frame(maxWidth: .infinity)
            .background(content: {
                RoundedRectangle(cornerRadius: 16)
                    .fill(Color.white)
                    .opacity(0.30)
            })
            .gesture(
                DragGesture(
                    minimumDistance: 5.0,
                    coordinateSpace: .global)
                .onChanged({ value in
                    if !taskDragActive {
                        taskDragActive = true
                        taskDragEndDone = false
                    }
                    actionValue = value.translation.width
                    opacityValue = max(1.0 - abs(actionValue) * 0.01, 0.0)
                    offsetValue = actionValue
                    if actionValue < actionThreshold {
                        if !taskDragEndDone {
                            taskDragEndDone = true
                        }
                    }
                })
                .onEnded({ value in
                    if actionValue >= actionThreshold {
                        taskDragActive = false

                        withAnimation {
                            actionValue = 0
                            opacityValue = 1.0
                            offsetValue = 0
                        }
                    } else if taskDragEndDone {
                        animateNextTask()
                        animateGestureForTask()
                    }
                })
            )
            .padding(.vertical, 8)
            .foregroundStyle(.primary)

            VStack {
                Text("Swipe for a new task.")
                    .foregroundStyle(.secondary)
                    .font(.system(size: 14))
                    .multilineTextAlignment(.center)
            }
        }
        .padding(30)
        .background {
            Image("background")
                .resizable()
                .scaledToFill()
                .padding(-80)
                .blur(radius: 150.0)
                .brightness(0.3)
        }
    }

    private func animateGestureForTask() {
        opacityValue = 0.0
        offsetValue = 150.0
        withAnimation(.spring(duration: 0.8, bounce: 0.1)) {
            offsetValue = 0.0
        }
        withAnimation(.easeOut(duration: 1.8)) {
            opacityValue = 1.0
        }
    }

    private func animateNextTask() {
        taskIndex += 1
        taskQuestion = "\(taskIndex) + \(taskIndex)"
    }
}

#Preview {
    SampleAnimationView()
}


SwiftUI Animation

 

www.admadic.de | webmaster@admadic.de | Legal Notice and Trademarks | Privacy
© 2005-2007 - admaDIC | All Rights Reserved
All other trademarks and/or registered trademarks are the property of their respective owners
Last Change: Sun Mar 30 09:34:00 2025 GMT