SwiftUI
Conditional Views
iOS Development
Swift Programming
Mobile App Design

Conditionally use view in SwiftUI

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

SwiftUI provides several ways to conditionally display views: if statements inside view builders, the ternary operator for inline conditions, Group for conditional blocks, and custom View extensions for conditional modifiers. The @ViewBuilder attribute enables writing control flow directly in view code. Understanding when to use each approach ensures clean, performant UI code.

Basic if/else in View Builders

swift
1import SwiftUI
2
3struct ProfileView: View {
4    @State private var isLoggedIn = false
5
6    var body: some View {
7        VStack {
8            if isLoggedIn {
9                Text("Welcome back!")
10                    .font(.title)
11                LogoutButton()
12            } else {
13                Text("Please sign in")
14                    .font(.title)
15                LoginButton()
16            }
17        }
18    }
19}

SwiftUI's @ViewBuilder allows if/else directly in the body property. Each branch can return different view types.

Showing or Hiding a View

swift
1struct NotificationBanner: View {
2    @State private var showBanner = true
3
4    var body: some View {
5        VStack {
6            // Option 1: if statement — removes from view hierarchy
7            if showBanner {
8                Text("New update available!")
9                    .padding()
10                    .background(Color.blue)
11                    .foregroundColor(.white)
12                    .cornerRadius(8)
13            }
14
15            // Option 2: opacity — keeps in hierarchy but invisible
16            Text("Hidden text")
17                .opacity(showBanner ? 0 : 1)
18
19            // Option 3: hidden modifier — keeps layout space
20            Text("Takes space but invisible")
21                .hidden()  // Always hidden; no conditional
22
23            Button("Toggle") {
24                withAnimation {
25                    showBanner.toggle()
26                }
27            }
28        }
29    }
30}

Key difference: if removes the view entirely (no layout space). .opacity(0) hides it visually but preserves layout. Choose based on whether you want the hidden view to affect spacing.

Ternary Operator for Simple Conditions

swift
1struct StatusView: View {
2    var isActive: Bool
3
4    var body: some View {
5        Text(isActive ? "Active" : "Inactive")
6            .foregroundColor(isActive ? .green : .red)
7            .font(isActive ? .headline : .subheadline)
8            .padding()
9            .background(isActive ? Color.green.opacity(0.1) : Color.red.opacity(0.1))
10            .cornerRadius(8)
11    }
12}

The ternary operator is best for toggling between two values of the same modifier.

Conditional Modifier Extension

swift
1extension View {
2    @ViewBuilder
3    func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
4        if condition {
5            transform(self)
6        } else {
7            self
8        }
9    }
10}
11
12// Usage
13struct CardView: View {
14    var isHighlighted: Bool
15
16    var body: some View {
17        Text("Card Content")
18            .padding()
19            .if(isHighlighted) { view in
20                view
21                    .background(Color.yellow)
22                    .border(Color.orange, width: 2)
23            }
24    }
25}

This extension conditionally applies modifiers without duplicating the entire view chain.

switch Statement

swift
1enum UserRole {
2    case admin, editor, viewer
3}
4
5struct DashboardView: View {
6    var role: UserRole
7
8    var body: some View {
9        VStack {
10            switch role {
11            case .admin:
12                AdminPanel()
13            case .editor:
14                EditorPanel()
15            case .viewer:
16                Text("Read-only access")
17            }
18        }
19    }
20}

Optional Binding with if-let

swift
1struct UserDetailView: View {
2    var user: User?
3
4    var body: some View {
5        VStack {
6            if let user = user {
7                Text(user.name)
8                    .font(.title)
9                Text(user.email)
10                    .font(.subheadline)
11            } else {
12                Text("No user selected")
13                    .foregroundColor(.secondary)
14            }
15        }
16    }
17}

Group for Conditional Blocks

swift
1struct SettingsView: View {
2    var isPremium: Bool
3
4    var body: some View {
5        List {
6            Section("General") {
7                Text("Notifications")
8                Text("Appearance")
9            }
10
11            // Conditionally include an entire section
12            if isPremium {
13                Section("Premium") {
14                    Text("Custom Themes")
15                    Text("Priority Support")
16                    Text("Advanced Analytics")
17                }
18            }
19        }
20    }
21}

AnyView for Dynamic Type Erasure

swift
1struct DynamicView: View {
2    var viewType: String
3
4    var body: some View {
5        // AnyView erases the concrete type — use sparingly
6        makeView(for: viewType)
7    }
8
9    @ViewBuilder
10    func makeView(for type: String) -> some View {
11        switch type {
12        case "text":
13            Text("Hello")
14        case "image":
15            Image(systemName: "star")
16        default:
17            EmptyView()
18        }
19    }
20}

Prefer @ViewBuilder over AnyView — it preserves type information and enables better SwiftUI diffing.

Animated Conditional Views

swift
1struct ExpandableCard: View {
2    @State private var isExpanded = false
3
4    var body: some View {
5        VStack {
6            Button("Toggle Details") {
7                withAnimation(.spring()) {
8                    isExpanded.toggle()
9                }
10            }
11
12            if isExpanded {
13                VStack(alignment: .leading) {
14                    Text("Detail line 1")
15                    Text("Detail line 2")
16                    Text("Detail line 3")
17                }
18                .transition(.opacity.combined(with: .slide))
19            }
20        }
21        .padding()
22    }
23}

Wrap the state change in withAnimation and add .transition() to the conditional view for smooth animations.

Common Pitfalls

  • Using AnyView unnecessarily: Wrapping conditional views in AnyView disables SwiftUI's structural identity and diff optimization. Use @ViewBuilder and if/else instead, which let SwiftUI efficiently track which branch is active and animate transitions.
  • Forgetting that if/else branches are different view identities: When an if/else switches branches, SwiftUI treats them as entirely different views and recreates state. If both branches have a TextField, the text is lost on switch. Use .opacity() or .disabled() to preserve state when toggling visibility.
  • Deeply nested conditional logic in view body: Multiple nested if/else statements make the view body hard to read and compile slowly. Extract conditional logic into computed properties or separate @ViewBuilder functions.
  • Not animating conditional view changes: Adding or removing a view with a plain if statement causes abrupt appearance/disappearance. Wrap the state change in withAnimation {} and add .transition(.opacity) to the view for smooth animations.
  • Conditional modifiers returning different types: view.padding(condition ? 10 : 0) works, but view.if(condition) { $0.background(Color.red) } without @ViewBuilder causes type mismatches. Always use the @ViewBuilder attribute on functions that return conditional views.

Summary

  • Use if/else in @ViewBuilder bodies for conditional views — this is the standard approach
  • Use the ternary operator for toggling modifier values (color, font, padding)
  • Use .opacity(0) or .hidden() to hide a view while preserving its layout space
  • Create a View extension with @ViewBuilder for conditional modifier application
  • Prefer @ViewBuilder over AnyView to preserve SwiftUI's structural diffing
  • Wrap state changes in withAnimation and add .transition() for animated conditional views

Course illustration
Course illustration

All Rights Reserved.