Skip to main content

Building Declarative UIs with SwiftUI

1. Creating SwiftUI Views

Property Values Description
View Text("Hello, World!") Basic SwiftUI view displaying text
View Image("icon") Displays an image resource
View Button("Tap me") { ... } Interactive button with action
View NavigationView { ... } Container for navigation stack
View ForEach(items) { item in ... } Dynamic list rendering

Example: Basic Text View

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

Example: Button with Action

struct ContentView: View {
    @State private var count = 0

    var body: some View {
        Button("Tap me") {
            count += 1
        }
    }
}
Note: SwiftUI views are value types and must conform to the View protocol.

2. Using Text and Label Views

Property Values Description
Text Text("Hello, World!") Displays static or dynamic text content
Label Label("Save", systemImage: "square.and.arrow.down") Combines text with a system or custom image

Example: Basic Text Usage

struct ContentView: View {
    var body: some View {
        Text("Welcome to SwiftUI")
            .font(.largeTitle)
    }
}

Example: Dynamic Text with Binding

struct CounterView: View {
    @State private var count = 0
    
    var body: some View {
        Text("Count: \(count)")
            .onTapGesture {
                count += 1
            }
    }
}

Example: Label with System Image

struct SaveButton: View {
    var body: some View {
        Label("Save", systemImage: "square.and.arrow.down")
            .padding()
    }
}
Note: The Text view supports localization via Text(LocalizedStringKey).
Warning: Avoid using Text inside a ForEach loop without a unique identifier; use id modifier to prevent UI flickering.

3. Using Button and Toggle

Property Values Description
Button Text("Tap me") Basic button with text label
Button Image("icon") Button with image label
Button Label("Save", systemImage: "square.and.arrow.down") Button with system image and text
Toggle isOn: Binding<Bool> Binds to a Boolean state variable
Toggle label: Text Label for the toggle control

Example: Basic Button

struct ContentView: View {
    var body: some View {
        Button("Press Me") {
            print("Button tapped!")
        }
    }
}

Example: Toggle with Binding

struct ContentView: View {
    @State private var isToggled = false

    var body: some View {
        Toggle("Enable Feature", isOn: $isToggled)
    }
}

Example: Button with Image

struct ContentView: View {
    var body: some View {
        Button(action: {
            // Action logic here
        }) {
            Image(systemName: "heart.fill")
                .foregroundColor(.red)
        }
    }
}
Note: The Button in SwiftUI is a stateless component that triggers an action when tapped. It supports various content types including text, images, and labels.
Note: The Toggle control is used to switch between two states (on/off) and requires a binding to a Boolean value.

4. Working with Image Views

Property Values Description
Image Image("imageName") Displays an image from the asset catalog
Image(systemName:) Image(systemName: "heart.fill") Displays a system SF Symbol image
Image(uiImage:) Image(uiImage: UIImage(named: "customImage")!) Displays a UIKit UIImage

Example: Displaying an Image from Asset Catalog

struct ContentView: View {
    var body: some View {
        Image("swiftLogo")
            .resizable()
            .aspectRatio(contentMode: .fit)
    }
}

Example: Using SF Symbols

struct ContentView: View {
    var body: some View {
        Image(systemName: "sun.max.fill")
            .foregroundColor(.yellow)
            .font(.system(size: 50))
    }
}

Example: Resizing and Cropping Images

struct ContentView: View {
    var body: some View {
        Image("heroImage")
            .resizable()
            .aspectRatio(contentMode: .fill)
            .frame(width: 200, height: 150)
    }
}
Note: Ensure image assets are added to the asset catalog in Xcode for proper deployment.

5. Using VStack, HStack, ZStack

SwiftUI provides three fundamental stacking views to arrange UI elements: VStack, HStack, and ZStack. These views are used to build declarative layouts by stacking elements vertically, horizontally, or on top of each other.

View Description Usage
VStack Arranges child views vertically (top to bottom). VStack { Text("Top"); Text("Bottom") }
HStack Arranges child views horizontally (left to right). HStack { Text("Left"); Text("Right") }
ZStack Overlays child views on top of each other, centered by default. ZStack { Text("Background"); Text("Foreground") }

Example: VStack Usage

struct ContentView: View {
    var body: some View {
        VStack(spacing: 10) {
            Text("Header")
                .font(.largeTitle)
            Text("Content")
                .font(.body)
            Text("Footer")
                .font(.caption)
        }
    }
}

Example: HStack Usage

struct ContentView: View {
    var body: some View {
        HStack {
            Image(systemName: "star")
                .foregroundColor(.yellow)
            Text("Rating")
                .font(.subheadline)
        }
    }
}

Example: ZStack Usage

struct ContentView: View {
    var body: some View {
        ZStack {
            Color.blue
                .frame(width: 200, height: 200)
            Text("Overlay")
                .foregroundColor(.white)
                .font(.largeTitle)
        }
    }
}
Note: VStack, HStack, and ZStack can be nested to create complex layouts. Each stacking view supports alignment, spacing, and padding modifiers to customize the arrangement.

6. Using List and ForEach

Property Value Description
List View A SwiftUI view that displays a list of data
ForEach View A SwiftUI view that iterates over a collection to build a list of views

Example: Basic List

struct ContentView: View {
    let items = ["Item 1", "Item 2", "Item 3"]
    
    var body: some View {
        List(items, id: \.self) { item in
            Text(item)
        }
    }
}

Example: ForEach with Custom Data

struct ContentView: View {
    let items = [
        Item(id: 1, name: "Apple"),
        Item(id: 2, name: "Banana"),
        Item(id: 3, name: "Cherry")
    ]
    
    var body: some View {
        List(items, id: \.id) { item in
            Text(item.name)
        }
    }
}

struct Item: Identifiable {
    let id: Int
    let name: String
}

Example: ForEach with Nested Views

struct ContentView: View {
    let items = ["Red", "Green", "Blue"]
    
    var body: some View {
        VStack {
            ForEach(items, id: \.self) { color in
                Text(color)
                    .foregroundColor(.init(color))
            }
        }
    }
}
Note: List and ForEach are fundamental for building dynamic UIs in SwiftUI. They provide a declarative way to handle collections of data.

7. Working with ScrollView

ScrollView is a fundamental SwiftUI view for creating scrollable content. It supports both vertical and horizontal scrolling, and can be customized with various modifiers to control behavior and appearance.

Modifier Description Example
.scrollContentBackground(_: Controls the background of the scrollable content area. .scrollContentBackground(.hidden)
.scrollIndicators(_: Controls visibility of scroll indicators. .scrollIndicators(.never)
.scrollPosition(_: Manages the current scroll position. .scrollPosition(.constant(.top))

Example: Basic ScrollView with Text

import SwiftUI

struct ContentView: View {
    var body: some View {
        ScrollView {
            ForEach(0..<100) { index in
                Text("Item \\(index)")
                    .padding()
            }
        }
    }
}

Example: Horizontal ScrollView

import SwiftUI

struct ContentView: View {
    var body: some View {
        ScrollView(.horizontal) {
            HStack {
                ForEach(0..<20) { index in
                    Rectangle()
                        .fill(Color.blue)
                        .frame(width: 100, height: 100)
                        .overlay(
                            Text("\\(index)")
                                .foregroundColor(.white)
                        )
                }
            }
        }
    }
}
Note: ScrollView is ideal for content that exceeds the screen size. It's important to consider performance when using large lists or complex views inside ScrollView.
Property Value Description
NavigationStack NavigationStack Container for navigation views in SwiftUI
NavigationLink NavigationLink Creates a link that navigates to another view
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationStack {
            List {
                NavigationLink("Go to Detail", destination: DetailView())
            }
        }
    }
}

struct DetailView: View {
    var body: some View {
        Text("This is the detail view")
    }
}

Example: Navigation with Data

struct ContentView: View {
    let items = ["Item 1", "Item 2", "Item 3"]
    
    var body: some View {
        NavigationStack {
            List(items, id: \.self) { item in
                NavigationLink(item, destination: DetailView(item: item))
            }
        }
    }
}

struct DetailView: View {
    let item: String
    
    var body: some View {
        Text("You selected: \(item)")
    }
}
Note: NavigationStack manages the navigation stack and handles back button behavior automatically.
Warning: NavigationLink must be inside a NavigationStack or NavigationSplitView to function properly.

9. Using TabView for Navigation

TabView is a powerful SwiftUI component that allows you to create tab-based navigation interfaces, similar to the native iOS tab bar. It's particularly useful for organizing content into distinct sections or views that users can switch between.

Property Description Example
TabView Root view for creating tab-based navigation TabView { ... }
.tabItem Defines the label and icon for each tab Text("Home").tabItem { Image(systemName: "house") }
.tag Uniquely identifies each tab for selection Text("Profile").tag("profile").tabItem { Image(systemName: "person") }
.selection Binds to a state variable to control which tab is selected @State private var selection = "home"

Example: Basic TabView Implementation

import SwiftUI

struct ContentView: View {
    @State private var selection = "home"

    var body: some View {
        TabView(selection: $selection) {
            Text("Home Content")
                .tabItem {
                    Image(systemName: "house")
                    Text("Home")
                }
                .tag("home")

            Text("Profile Content")
                .tabItem {
                    Image(systemName: "person")
                    Text("Profile")
                }
                .tag("profile")
        }
    }
}
Note: The .tag is used to identify each tab and should be unique within the TabView. It is used in conjunction with .selection to control which view is displayed.

Example: TabView with Nested Navigation

import SwiftUI

struct ContentView: View {
    @State private var selection = "home"

    var body: some View {
        TabView(selection: $selection) {
            NavigationStack {
                Text("Home")
                    .navigationTitle("Home")
            }
            .tabItem {
                Image(systemName: "house")
                Text("Home")
            }
            .tag("home")

            NavigationStack {
                Text("Settings")
                    .navigationTitle("Settings")
            }
            .tabItem {
                Image(systemName: "gear")
                Text("Settings")
            }
            .tag("settings")
        }
    }
}

10. Applying View Modifiers

Modifier Description Usage
.padding() Adds padding around the view Text("Hello").padding()
.frame(width:height:alignment:) Sets the frame size and alignment Image("icon").frame(width: 50, height: 50)
.background() Applies a background to the view Text("Hello").background(Color.blue)
.foregroundColor() Changes the text color Text("Hello").foregroundColor(.red)
.cornerRadius() Rounds the corners of a view Rectangle().cornerRadius(10)
.border() Adds a border around the view Text("Hello").border(Color.gray, width: 2)
.shadow() Adds a shadow effect Text("Hello").shadow(radius: 5)
.overlay() Overlays another view on top Text("Hello").overlay(Rectangle().fill(Color.red))

Example: Combining Modifiers

Text("Hello World")
    .padding()
    .frame(width: 200, height: 100)
    .background(Color.gray)
    .cornerRadius(10)
    .foregroundColor(.white)

11. Understanding View Composition

SwiftUI's declarative UI framework is built around the concept of view composition, where complex user interfaces are constructed by combining smaller, reusable views. This approach promotes modularity, reusability, and maintainability of UI code.

View Type Description Usage Example
View The base protocol for all SwiftUI views. Every view must conform to this protocol. struct ContentView: View { ... }
Container View Views that can contain other views, such as VStack, HStack, and ZStack.
VStack {
     Text("Hello")
     Text("World")
 }
Leaf View Views that do not contain other views, such as Text, Image, and Button. Text("Hello World")

Example: Composing a Simple UI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 20) {
            Text("Welcome to SwiftUI")
                .font(.largeTitle)
            
            HStack {
                Image(systemName: "star.fill")
                    .foregroundColor(.yellow)
                Text("5 Stars")
            }
            
            Button("Tap Me") {
                print("Button tapped!")
            }
        }
    }
}
Note: The body property in a View must return a single view or a view builder expression. SwiftUI uses the some View return type to ensure that only valid views are returned.

Key Concepts of View Composition

  • Modularity: Views can be broken down into smaller, reusable components.
  • Nesting: Views can be nested inside other views to create complex layouts.
  • Reusability: Custom views can be reused across different parts of an app.
  • Flexibility: SwiftUI's view composition allows for dynamic and adaptive UIs.

Was this article helpful?