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 - 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)
}
}
}
Navigation Components
NavigationStack
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
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 gridLazyHGrid→ 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()
}
}