Author: saqibkhan

  • SwiftUI Modifiers

    Style views by chaining modifiers

    Apply multiple modifiers to a view to adjust typography, color, spacing, and backgrounds.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct ModifiersDemo: View {
      var body: some View {
    
    Text("Hello")
      .font(.title)
      .foregroundStyle(.blue)
      .padding()
      .background(.blue.opacity(0.1))
      .cornerRadius(8)
    } }

    The example above shows a text view styled with multiple modifiers.

  • SwiftUI Modifiers & ViewBuilder

    Modifiers

    Modifiers return new views with applied changes such as padding, font, and color.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct ModifiersDemo: View {
      var body: some View {
    
    Text("Hello")
      .font(.title)
      .foregroundStyle(.blue)
      .padding()
      .background(.blue.opacity(0.1))
      .cornerRadius(8)
    } }

    ViewBuilder

    Use @ViewBuilder to compose multiple child views in a single return position.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    @ViewBuilder
    func InfoRow(_ title: String, _ value: String) -> some View {
      HStack { Text(title).bold(); Spacer(); Text(value) }
    }
    
    struct ViewBuilderDemo: View {
      var body: some View {
    
    VStack(spacing: 8) {
      InfoRow("Name", "SwiftUI")
      InfoRow("Version", "5+")
    }
    .padding()
    } }
  • SwiftUI Gestures RotationGesture

    RotationGesture

    Rotate views with two fingers using RotationGesture and apply the angle via .rotationEffect.


    Syntax

    Rotation: Use RotationGesture() to read an Angle and apply it with .rotationEffect(angle).


    Rotate and Reset

    Rotate the image with two fingers. Releasing animates back to 0°.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct RotationDemo: View {
      @State private var angle = Angle.zero
      var body: some View {
    
    Image(systemName: "arrow.2.circlepath")
      .font(.system(size: 48))
      .rotationEffect(angle)
      .gesture(
        RotationGesture()
          .onChanged { value in angle = value }
          .onEnded { _ in withAnimation(.easeInOut) { angle = .zero } }
      )
    } }

    In the example above, the image can be rotated with two fingers.

    Releasing animates back to 0°.


    Accumulate Rotation

    Accumulate the rotation so each gesture adds to the total angle.

    Display the angle in degrees.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct RotationAccumDemo: View {
      @State private var total: Angle = .zero
      @State private var current: Angle = .zero
      var body: some View {
    
    VStack(spacing: 12) {
      Image(systemName: "arrow.triangle.2.circlepath")
        .font(.system(size: 48))
        .rotationEffect(total + current)
        .gesture(
          RotationGesture()
            .onChanged { value in current = value }
            .onEnded { value in total += value; current = .zero }
        )
      Text("Angle: \(Int((total + current).degrees))°")
    }
    .padding()
    } }
  • SwiftUI Gestures MagnificationGesture

    MagnificationGesture

    Pinch to zoom content using MagnificationGesture, often combined with .scaleEffect.


    Syntax

    Magnify: Use MagnificationGesture() to get a scale factor and apply it with .scaleEffect(scale).


    Pinch to Zoom

    Pinch the image to zoom in/out. Releasing snaps back to the original size.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct MagnifyDemo: View {
      @State private var scale: CGFloat = 1
      var body: some View {
    
    Image(systemName: "photo")
      .resizable().scaledToFit().frame(height: 120)
      .scaleEffect(scale)
      .gesture(
        MagnificationGesture()
          .onChanged { value in scale = value }
          .onEnded { _ in withAnimation(.spring()) { scale = 1 } }
      )
    } }

    In the example above, pinching the image zooms in/out.

    Releasing snaps back to the original size.


    Clamp Scale Range

    Limit the zoom between 0.5x and 2x to avoid miniaturization or excessive enlargement.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct MagnifyClampedDemo: View {
      @State private var scale: CGFloat = 1
      let minS: CGFloat = 0.5
      let maxS: CGFloat = 2.0
      func clamp(_ v: CGFloat) -> CGFloat { min(max(v, minS), maxS) }
      var body: some View {
    
    Image(systemName: "photo")
      .resizable().scaledToFit().frame(height: 120)
      .scaleEffect(scale)
      .gesture(
        MagnificationGesture()
          .onChanged { value in scale = clamp(value) }
          .onEnded { _ in withAnimation(.easeInOut) { scale = 1 } }
      )
    } }

    In the example above, the zoom is clamped between 0.5x and 2x.

  • SwiftUI Gestures Composing Gestures

    Composing Gestures

    Combine gestures using .simultaneousGesture or .highPriorityGesture and coordinate interactions.


    Syntax

    Compose: Add .simultaneousGesture() to run together, or .highPriorityGesture() to give precedence to one gesture.


    Simultaneous Tap + Drag

    Both gestures run: taps increment a counter while dragging changes color.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct ComposeSimultaneousDemo: View {
      @State private var tapped = 0
      @State private var dragged = false
      var body: some View {
    
    Rectangle()
      .fill(dragged ? .orange : .purple)
      .frame(height: 120)
      .overlay(Text("taps: \(tapped)"))
      .simultaneousGesture(TapGesture().onEnded { tapped += 1 })
      .gesture(DragGesture().onChanged { _ in dragged = true }.onEnded { _ in dragged = false })
    } }

    In the example above, both the tap and drag gestures run.


    High Priority Drag Over Tap

    Drag takes precedence over tap: while dragging, taps do not increment the counter.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct ComposePriorityDemo: View {
      @State private var tapped = 0
      @State private var dragging = false
      var body: some View {
    
    Rectangle()
      .fill(dragging ? .orange : .purple)
      .frame(height: 120)
      .overlay(Text("taps: \(tapped)"))
      .highPriorityGesture(DragGesture().onChanged { _ in dragging = true }.onEnded { _ in dragging = false })
      .gesture(TapGesture().onEnded { if !dragging { tapped += 1 } })
    } }
  • SwiftUI Gestures DragGesture

    DragGesture

    Track finger movement and update view position or state in response to a DragGesture.


    Syntax

    Drag: Attach DragGesture() and handle .onChanged/.onEnded.

    Apply translation via .offset.


    Drag to Move

    Drag the label to move it around. Releasing snaps it back using a spring animation.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct DragDemo: View {
      @State private var offset: CGSize = .zero
      var body: some View {
    
    Text("Drag me")
      .padding(12)
      .background(.blue.opacity(0.1))
      .cornerRadius(8)
      .offset(offset)
      .gesture(
        DragGesture()
          .onChanged { value in offset = value.translation }
          .onEnded { _ in withAnimation(.spring()) { offset = .zero } }
      )
    } }

    In the example above, the label is dragged and released.

    The .onEnded handler snaps it back using a spring animation.


    Constrain Drag Within Bounds

    Clamp the drag translation so the view stays inside a container.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct DragBoundsDemo: View {
      @State private var offset: CGSize = .zero
      let limit: CGFloat = 120
      func clamp(_ v: CGFloat) -> CGFloat { min(max(v, -limit), limit) }
      var body: some View {
    
    ZStack {
      RoundedRectangle(cornerRadius: 12)
        .stroke(.gray.opacity(0.4), lineWidth: 1)
        .frame(width: 280, height: 160)
      Circle()
        .fill(.blue.opacity(0.2))
        .frame(width: 44, height: 44)
        .offset(x: offset.width, y: offset.height)
        .gesture(
          DragGesture()
            .onChanged { value in
              offset = CGSize(width: clamp(value.translation.width), height: clamp(value.translation.height))
            }
            .onEnded { _ in withAnimation(.spring()) { offset = .zero } }
        )
    }
    .padding()
    } }

    In the example above, the circle is dragged and released.

  • SwiftUI Gestures LongPressGesture

    LongPressGesture

    Detect a sustained press using LongPressGesture to trigger state changes.


    Syntax

    Long press handler: .onLongPressGesture(minimumDuration: 0.5) { ... } or LongPressGesture(minimumDuration:) with .onEnded.


    Toggle on Long Press

    Hold for 0.5 seconds to toggle the label between “Hold me” and “Pressed”.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct LongPressDemo: View {
      @State private var pressed = false
      var body: some View {
    
    Text(pressed ? "Pressed" : "Hold me")
      .padding(12)
      .background(.blue.opacity(0.1))
      .cornerRadius(8)
      .onLongPressGesture(minimumDuration: 0.5) { pressed.toggle() }
    } }

    In the example above, the label toggles between “Hold me” and “Pressed” when held for 0.5 seconds.



    Show Progress During Long Press

    Track the in-progress state and scale the view while pressing using LongPressGesture with .updating.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct LongPressProgressDemo: View {
      @GestureState private var isPressing = false
      @State private var done = false
      var body: some View {
    
    Circle()
      .fill(done ? .green : .gray)
      .frame(width: 80, height: 80)
      .scaleEffect(isPressing ? 0.9 : 1)
      .gesture(
        LongPressGesture(minimumDuration: 0.6)
          .updating($isPressing) { value, state, _ in state = value }
          .onEnded { _ in done.toggle() }
      )
    } }
  • SwiftUI Gestures

    SwiftUI Gestures

    Handle taps, drags, and other interactions with .gesture and built-in gesture recognizers.


    Tap and Long Press

    Handle taps and long presses with .onTapGesture and .onLongPressGesture.


    Syntax:

    • .onTapGesture { ... }
    • .onLongPressGesture(minimumDuration:perform:)

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct TapLongPressDemo: View {
      @State private var on = false
      @State private var pressed = false
      var body: some View {
    
    Circle()
      .fill(on ? .green : .gray)
      .frame(width: 80, height: 80)
      .scaleEffect(pressed ? 0.9 : 1)
      .onTapGesture { on.toggle() }
      .onLongPressGesture(minimumDuration: 0.5) { pressed.toggle() }
    } }

    This example toggles color on tap and briefly scales the circle on a long-press.


    DragGesture

    Track finger movement by attaching a DragGesture to update an offset.

    Syntax: .gesture(DragGesture().onChanged { value in ... }.onEnded { ... })

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct DragDemo: View {
      @State private var offset: CGSize = .zero
      var body: some View {
    
    Text("Drag me")
      .padding(12)
      .background(.blue.opacity(0.1))
      .cornerRadius(8)
      .offset(offset)
      .gesture(
        DragGesture()
          .onChanged { value in offset = value.translation }
          .onEnded { _ in withAnimation(.spring()) { offset = .zero } }
      )
    } }

    This example follows the finger while dragging and springs back to the origin on release.



    Combining Gestures

    Use .simultaneousGesture or .highPriorityGesture to coordinate multiple gestures.

    Syntax:

    • .simultaneousGesture(TapGesture())
    • .highPriorityGesture(DragGesture())

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct CombineGesturesDemo: View {
      @State private var tapped = 0
      @State private var dragged = false
      var body: some View {
    
    Rectangle()
      .fill(dragged ? .orange : .purple)
      .frame(height: 120)
      .overlay(Text("taps: \(tapped)"))
      .simultaneousGesture(TapGesture().onEnded { tapped += 1 })
      .highPriorityGesture(DragGesture().onChanged { _ in dragged = true }.onEnded { _ in dragged = false })
    } }

    This example counts taps while also reacting to drags, demonstrating gesture composition.

  • SwiftUI Animations Animation Curves

    Animation Curves

    Choose timing functions like .easeIn.easeOut.easeInOut, and .linear to shape motion.


    Syntax

    Timing curves: withAnimation(.easeInOut(duration: 1)) { state = ... }.

    Choose .easeIn.easeOut.easeInOut, or .linear to change acceleration.


    EaseIn vs easeOut

    Tap buttons to move the dot with different curves. .easeIn starts slow and speeds up; .easeOut starts fast and slows down.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct CurvesDemo: View {
      @State private var x: CGFloat = 0
      var body: some View {
    
    VStack(spacing: 12) {
      HStack { Circle().frame(width: 24, height: 24).offset(x: x); Spacer() }
      HStack(spacing: 12) {
        Button("EaseIn") { withAnimation(.easeIn(duration: 1)) { x = 240 } }
        Button("EaseOut") { withAnimation(.easeOut(duration: 1)) { x = 0 } }
      }
    }
    .padding()
    } }

    In the example above, the dot moves with different curves using .easeIn and .easeOut.



    Linear vs easeInOut

    Compare a constant-speed (.linear) motion with a smooth accelerate/decelerate (.easeInOut).

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct CurvesCompareDemo: View {
      @State private var go = false
      var body: some View {
    
    VStack(spacing: 16) {
      HStack { Circle().frame(width: 16, height: 16).offset(x: go ? 240 : 0); Spacer() }
        .animation(.linear(duration: 1), value: go)
      HStack { Circle().frame(width: 16, height: 16).offset(x: go ? 240 : 0); Spacer() }
        .animation(.easeInOut(duration: 1), value: go)
      Button(go ? "Reset" : "Animate") { go.toggle() }
    }
    .padding()
    } }
  • SwiftUI Animations Spring Animations

    SwiftUI Animations: Spring Animations

    Use .spring() animations to simulate mass-spring-damper motion with configurable stiffness and damping.


    Syntax

    Spring: withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) { state.toggle() }response controls speed, dampingFraction controls overshoot/bounce.


    Basic Spring Toggle

    Tap the button to toggle the circle’s size with a spring animation configured by response and dampingFraction.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct SpringDemo: View {
      @State private var on = false
      var body: some View {
    
    VStack(spacing: 12) {
      Circle()
        .fill(on ? .green : .gray)
        .frame(width: on ? 120 : 60, height: on ? 120 : 60)
      Button("Toggle") {
        withAnimation(.spring(response: 0.4, dampingFraction: 0.6)) { on.toggle() }
      }
    }
    .padding()
    } }


    Tuned Spring Parameters

    Experiment with a bouncier spring by lowering damping and changing response. Multiple shapes animate with different timing.

    Example

    Demo.swift

    ContentView.swift

    App.swift

    import SwiftUI
    
    struct SpringTunedDemo: View {
      @State private var on = false
      var body: some View {
    
    VStack(spacing: 16) {
      RoundedRectangle(cornerRadius: 12)
        .fill(.blue.opacity(0.2))
        .frame(width: on ? 220 : 140, height: 40)
        .animation(.spring(response: 0.25, dampingFraction: 0.45), value: on)
      Circle()
        .fill(.orange.opacity(0.4))
        .frame(width: on ? 80 : 40, height: on ? 80 : 40)
        .animation(.spring(response: 0.5, dampingFraction: 0.65), value: on)
      Button(on ? "Reset" : "Bounce") { on.toggle() }
    }
    .padding()
    } }