Post

SwiftUI Deep Dive

SwiftUI is a modern framework to develop user interfaces for all of Apple's platforms such as iOS, watchOS, macOS, tvOS, iPadOS, and visionOS. It was developed by Apple in 2019 as a replacement of traditional frameworks such as UIKit.

SwiftUI Deep Dive

SwiftUI - Overview

Declarative Syntax

SwiftUI uses declarative syntaxes to develop an App. Declarative syntaxes allow developers to describe the user interface and its behaviour and the rest of the implementation is done by the SwiftUI itself. This approach simplifies the code so that it would be easy to understand and reuse. It focuses on what should be displayed rather than how it is rendered.

Example:

1
2
3
4
5
struct ContentView: View {
   var body: some View {
      Text("Hello")
   }
}

Layout

SwiftUI supports layout systems based on stacks such as VStack, HStack, and ZStack. This system simplifies the alignment of components in the current view. It can also allow nesting of views.

1
2
3
4
5
6
7
struct ContentView: View {   
   var body: some View {
      VStack{
         Text("TutorialsPoint").font(.title)
      }
   }
}

Views and Modifiers

SwiftUI provides various in-built views such as Text, Image, Toggle, etc., and modifiers such as .font, .fill, .stroke, .foregroundColor, etc. Views are the fundamental building block of the interface whereas modifiers are used to change the appearance of the views. Using these views and modifiers we can create easy or complex user interfaces with few lines of code.

1
2
3
4
5
struct ContentView: View {
   var body: some View {
      Text("TutorialsPoint").font(.title)
   }
}

Gesture

Gestures are used to add interactivity to the interface by responding to the user inputs like tap, long press, drag, hover, etc. SwiftUI provides some in-built gestures like Tap, Long Press, Drag, Rotation, etc., using these gestures we can create an interactive UI.

1
2
3
4
5
6
7
struct ContentView: View {
   var body: some View {
      Text("TutorialsPoint").onTapGesture {
         // Handling tap gesture
      }
   }
}

Animation

In SwiftUI, we can animate any component very easily with the help of the .withAnimation() modifier. It also provides inbuilt animations and transitions which we can easily apply on the UI components. Animation enhances the user experience of the app and can improve the interactivity of the App. We can create custom animation very easily.

1
2
3
4
5
6
7
8
9
10
11
struct ContentView: View {
   @State private var size: CGFloat = 2.0

   var body: some View {
      Button("Tap me to see the magic") {
         withAnimation {
            self.size *= 2.5
         }
      }.scaleEffect(size)
   }
}

UI Controls

SwiftUI supports various in-built UI controls such as buttons, sliders, text fields, pickers, etc. Controls are the most essential part of the UI using these controls developers can easily develop user-friendly apps for Apple’s platforms.

1
2
3
4
5
6
7
struct ContentView: View {
   var body: some View {
      Button(action:{
         // Hanldle button action
      })
   }
}

Text & Display Components

Text

Text is used to display read-only text in SwiftUI.

1
2
3
4
5
6
7
8
struct ContentView: View {
    
    var body: some View {
        
        // Display simple text
        Text("Hello, SwiftUI!")
    }
}

Styled Text

Text can be styled with font, color, weight, alignment, and more.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct ContentView: View {
    
    var body: some View {
        
        // Styled text
        Text("Welcome to SwiftUI")
            .font(.title)
            .fontWeight(.bold)
            .foregroundColor(.blue)
            .multilineTextAlignment(.center)
            .padding()
    }
}

Label

Label displays text with an icon.

1
2
3
4
5
6
7
8
struct ContentView: View {
    
    var body: some View {
        
        // Label with SF Symbol icon
        Label("Settings", systemImage: "gear")
    }
}

Image

Image is used to display images from assets or system icons.

1
2
3
4
5
6
7
8
9
10
struct ContentView: View {
    
    var body: some View {
        
        // Display SF Symbol image
        Image(systemName: "star.fill")
            .font(.largeTitle)
            .foregroundColor(.yellow)
    }
}

Asset Image

Image can display images added to the Assets folder.

1
2
3
4
5
6
7
8
9
10
11
struct ContentView: View {
    
    var body: some View {
        
        // Display image from Assets.xcassets
        Image("profile_photo")
            .resizable()
            .scaledToFit()
            .frame(width: 150, height: 150)
    }
}

AsyncImage

AsyncImage loads and displays images from a remote URL.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct ContentView: View {
    
    var body: some View {
        
        // Load image from URL
        AsyncImage(url: URL(string: "https://example.com/image.jpg")) { image in
            
            // Loaded image view
            image
                .resizable()
                .scaledToFit()
            
        } placeholder: {
            
            // Placeholder while loading
            ProgressView()
        }
        .frame(width: 200, height: 200)
    }
}

Spacer

Spacer creates flexible empty space between views.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct ContentView: View {
    
    var body: some View {
        
        HStack {
            
            Text("Left")
            
            // Creates flexible space
            Spacer()
            
            Text("Right")
        }
        .padding()
    }
}

Divider

Divider adds a horizontal or vertical separator line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct ContentView: View {
    
    var body: some View {
        
        VStack {
            
            Text("Top Content")
            
            // Separator line
            Divider()
            
            Text("Bottom Content")
        }
        .padding()
    }
}

UI Controls

Button

SwiftUI provides a built-in Button component that is used to trigger actions when the user taps on it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct ContentView: View {
    
    var body: some View {
        
        // Button component
        Button(action: {
            
            // Handle button tap action
            print("Button tapped")
            
        }) {
            
            // Button UI content
            Text("Tap Me")
        }
    }
}

Toggle

Toggle is used to switch between ON and OFF states.

1
2
3
4
5
6
7
8
9
10
struct ContentView: View {
    
    // Stores toggle state
    @State private var isEnabled = false
    
    var body: some View {
        
        Toggle("Enable Notification", isOn: $isEnabled)
    }
}

Slider

Slider allows users to select a value from a range.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct ContentView: View {
    
    // Slider current value
    @State private var volume: Double = 50
    
    var body: some View {
        
        VStack {
            
            // Display slider value
            Text("Volume: \(Int(volume))")
            
            // Slider component
            Slider(
                value: $volume,
                in: 0...100
            )
        }
        .padding()
    }
}

Stepper

Stepper increases or decreases numeric values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ContentView: View {
    
    // Counter value
    @State private var quantity = 1
    
    var body: some View {
        
        Stepper(
            "Quantity: \(quantity)",
            value: $quantity,
            in: 1...10
        )
        .padding()
    }
}

TextField

TextField is used for single-line text input.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ContentView: View {
    
    // Stores user input
    @State private var username = ""
    
    var body: some View {
        
        TextField(
            "Enter username",
            text: $username
        )
        .padding()
        .textFieldStyle(.roundedBorder)
    }
}

SecureField

SecureField hides typed characters for passwords.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct ContentView: View {
    
    // Password value
    @State private var password = ""
    
    var body: some View {
        
        SecureField(
            "Enter password",
            text: $password
        )
        .padding()
    }
}

TextEditor

TextEditor is used for multi-line text input.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct ContentView: View {
    
    // Stores long text
    @State private var description = ""
    
    var body: some View {
        
        TextEditor(text: $description)
            .frame(height: 200)
            .border(Color.gray)
            .padding()
    }
}

Picker

Picker allows users to choose one option from multiple choices.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct ContentView: View {
    
    // Selected option
    @State private var selectedFruit = "Apple"
    
    // Picker options
    let fruits = ["Apple", "Banana", "Orange"]
    
    var body: some View {
        
        Picker(
            "Select Fruit",
            selection: $selectedFruit
        ) {
            
            ForEach(fruits, id: \.self) { fruit in
                
                Text(fruit)
            }
        }
        .pickerStyle(.menu)
    }
}

DatePicker

DatePicker allows users to select dates and times.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct ContentView: View {
    
    // Selected date
    @State private var selectedDate = Date()
    
    var body: some View {
        
        DatePicker(
            "Select Date",
            selection: $selectedDate
        )
        .padding()
    }
}

ColorPicker

ColorPicker allows users to choose colors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct ContentView: View {
    
    // Selected color
    @State private var selectedColor = Color.blue
    
    var body: some View {
        
        ColorPicker(
            "Choose Color",
            selection: $selectedColor
        )
        .padding()
    }
}

ProgressView

ProgressView displays loading or progress status.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ContentView: View {
    
    var body: some View {
        
        VStack {
            
            // Circular loader
            ProgressView()
            
            // Linear progress bar
            ProgressView(value: 0.7)
        }
        .padding()
    }
}

Layout Components

VStack

VStack arranges views vertically.

1
2
3
4
5
6
7
8
9
10
11
12
struct ContentView: View {
    
    var body: some View {
        
        VStack {
            
            Text("First Item")
            Text("Second Item")
            Text("Third Item")
        }
    }
}

HStack

HStack arranges views horizontally.

1
2
3
4
5
6
7
8
9
10
11
struct ContentView: View {
    
    var body: some View {
        
        HStack {
            
            Image(systemName: "star.fill")
            Text("Favorite")
        }
    }
}

ZStack

ZStack overlays views on top of each other.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ContentView: View {
    
    var body: some View {
        
        ZStack {
            
            // Background color
            Color.blue
            
            // Foreground text
            Text("Hello SwiftUI")
                .foregroundColor(.white)
        }
    }
}

NavigationStack manages app navigation.

1
2
3
4
5
6
7
8
9
10
11
struct ContentView: View {
    
    var body: some View {
        
        NavigationStack {
            
            Text("Home Screen")
                .navigationTitle("Home")
        }
    }
}

NavigationLink navigates to another screen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct ContentView: View {
    
    var body: some View {
        
        NavigationStack {
            
            NavigationLink("Open Details") {
                
                // Destination screen
                Text("Details Screen")
            }
        }
    }
}

TabView

TabView creates bottom tab navigation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct ContentView: View {
    
    var body: some View {
        
        TabView {
            
            Text("Home Screen")
                .tabItem {
                    
                    Image(systemName: "house")
                    Text("Home")
                }
            
            Text("Profile Screen")
                .tabItem {
                    
                    Image(systemName: "person")
                    Text("Profile")
                }
        }
    }
}

List Components

List

List displays scrollable rows of data.

1
2
3
4
5
6
7
8
9
10
11
12
13
struct ContentView: View {
    
    // Sample data
    let fruits = ["Apple", "Banana", "Orange"]
    
    var body: some View {
        
        List(fruits, id: \.self) { fruit in
            
            Text(fruit)
        }
    }
}

ScrollView

ScrollView creates a scrollable container.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct ContentView: View {
    
    var body: some View {
        
        ScrollView {
            
            VStack(spacing: 20) {
                
                ForEach(1...20, id: \.self) { item in
                    
                    Text("Item \(item)")
                }
            }
        }
    }
}

Alerts & Sheets

Alert

Alert shows important popup messages.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct ContentView: View {
    
    // Controls alert visibility
    @State private var showAlert = false
    
    var body: some View {
        
        Button("Show Alert") {
            
            showAlert = true
        }
        .alert(
            "Warning",
            isPresented: $showAlert
        ) {
            
            Button("OK", role: .cancel) {
                
                // Handle OK action
            }
        }
    }
}

Sheet

Sheet presents a modal screen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct ContentView: View {
    
    // Controls sheet visibility
    @State private var showSheet = false
    
    var body: some View {
        
        Button("Open Sheet") {
            
            showSheet = true
        }
        .sheet(isPresented: $showSheet) {
            
            // Sheet content
            Text("This is a sheet view")
        }
    }
}

Shapes

Circle

Circle creates circular shapes.

1
2
3
4
5
6
7
8
9
10
11
12
struct ContentView: View {
    
    var body: some View {
        
        Circle()
            .fill(Color.blue)
            .frame(
                width: 120,
                height: 120
            )
    }
}

Rectangle

Rectangle creates rectangular shapes.

1
2
3
4
5
6
7
8
9
10
11
12
struct ContentView: View {
    
    var body: some View {
        
        Rectangle()
            .fill(Color.red)
            .frame(
                width: 200,
                height: 100
            )
    }
}

RoundedRectangle

RoundedRectangle creates rectangles with rounded corners.

1
2
3
4
5
6
7
8
9
10
11
12
struct ContentView: View {
    
    var body: some View {
        
        RoundedRectangle(cornerRadius: 20)
            .fill(Color.green)
            .frame(
                width: 200,
                height: 100
            )
    }
}

State Management

@State

@State stores local mutable data inside a view.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct ContentView: View {
    
    // Local state variable
    @State private var count = 0
    
    var body: some View {
        
        VStack {
            
            Text("Count: \(count)")
            
            Button("Increase") {
                
                // Update state
                count += 1
            }
        }
    }
}

@Binding

@Binding shares state between parent and child views.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct ParentView: View {
    
    // Parent state
    @State private var isOn = false
    
    var body: some View {
        
        ChildView(isOn: $isOn)
    }
}

struct ChildView: View {
    
    // Binding variable
    @Binding var isOn: Bool
    
    var body: some View {
        
        Toggle("Enable", isOn: $isOn)
    }
}

@StateObject

@StateObject creates and owns observable objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class CounterViewModel: ObservableObject {
    
    // Published value
    @Published var count = 0
}

struct ContentView: View {
    
    // Create observable object
    @StateObject private var viewModel = CounterViewModel()
    
    var body: some View {
        
        VStack {
            
            Text("Count: \(viewModel.count)")
            
            Button("Increase") {
                
                viewModel.count += 1
            }
        }
    }
}

Frames and Alignment

frame()

Controls size and alignment.

1
2
3
.frame(width: 200, height: 100)

.frame(maxWidth: .infinity, alignment: .leading)

padding()

Adds spacing around a view.

1
2
3
.padding()

.padding(16)

alignmentGuide()

Custom alignment control.

1
2
3
.alignmentGuide(.firstTextBaseline) { d in
    d[.bottom]
}

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import SwiftUI

struct FrameDemo: View {
    
    var body: some View {
        
        VStack(spacing: 16) {
            
            ZStack(alignment: .topLeading) {
                Color.yellow.opacity(0.2)
                
                Text("Top Left")
                    .padding(6)
            }
            .frame(width: 200, height: 100)
            
            HStack {
                Text("Left")
                Spacer()
                Text("Right")
            }
            .frame(maxWidth: .infinity, alignment: .leading)
        }
        .padding()
    }
}

SwiftUI Layout: Grids

SwiftUI grids are used to display items in rows and columns.

Lazy Grids

SwiftUI provides:

  • LazyVGrid → Vertical grid
  • LazyHGrid → Horizontal grid

They load items lazily for better performance.

LazyVGrid

Displays items vertically in grid format.

1
2
3
LazyVGrid(columns: columns, spacing: 12) {
    
}

GridItem Defines column or row layout.

Flexible Grid

1
2
3
4
let columns = [
    GridItem(.flexible()),
    GridItem(.flexible())
]
  • Automatically adjusts item width.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import SwiftUI

struct GridDemo: View {
    
    let columns = [
        GridItem(.flexible()),
        GridItem(.flexible())
    ]
    
    var body: some View {
        
        LazyVGrid(columns: columns, spacing: 12) {
            
            ForEach(1...6, id: \.self) { i in
                
                Text("Item \(i)")
                    .frame(maxWidth: .infinity)
                    .padding(12)
                    .background(.blue.opacity(0.1))
                    .cornerRadius(8)
            }
        }
        .padding()
    }
}

Adaptive Grid

Automatically fits as many items as possible in a row.

Adaptive Grid Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import SwiftUI

struct AdaptiveGridDemo: View {
    
    let columns = [
        GridItem(.adaptive(minimum: 100), spacing: 12)
    ]
    
    var body: some View {
        
        LazyVGrid(columns: columns, spacing: 12) {
            
            ForEach(1...12, id: \.self) { i in
                
                Text("Card \(i)")
                    .frame(maxWidth: .infinity, minHeight: 60)
                    .background(.green.opacity(0.12))
                    .cornerRadius(8)
            }
        }
        .padding()
    }
}
This post is licensed under CC BY 4.0 by the author.