SwiftUI

up:: Swift ⚐

My notes

Loose notes

SwiftUI fundamentals course

Course: https://youtu.be/b1oC7sLIgpI?feature=shared&t=18755

  • Stacks
    • Horizontal/Vertical: HStack, VStack
    • Background/Foreground: ZStack
  • Modifiers wrap a View in another View. So the order of modifiers matters.
    • Like wrapping an element in divs

Scenes

Are like windows

Animate

withAnimation {
	// action
}
 
// on component:
.contentTransition(.numericText(value: rating))

@State

When you mark a variable with @State, SwiftUI handles its storage and provides it back to the View to read and write.

@Binding

A Binding creates a two-way reference to the State of some other view.

You can bind a variable with @Binding and $varName. Whenever the variable in the child changes, it sets that variable on the parents.

This is similar to v-model in Vue.

Basic button

            Button(action: {
                
            }, label: {
                Text("Learn more")
                    .font(.title2)
                    .fontWeight(.semibold)
                    .frame(width: 280, height: 50)
                    .background(Color.red)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            })
 

Create a big struct with all error messages

struct AlertItem {
    let title: String
    let message: String
    let dismissButtonText: String
}
 
struct AlertContext {
    static let invalidDeviceInput = AlertItem(title: "my error", message: "Hello there", dismissButtonText: "Close")
}

You create one alert and then pass in different AlertItem content.

Data-driven navigation. Based on data type, you show different screens.

    var body: some View {
        NavigationStack {
            ScrollView {
                LazyVGrid(columns: columns) {
                    ForEach(MockData.frameworks) { framework in
                        NavigationLink(value: framework) {
                            FrameworkTitleView(framework: framework)
                        }
                    }
                }
            }
                .navigationTitle(" Frameworks")
                .navigationDestination(for: Framework.self) { framework in
                    FrameworkDetailView(framework: framework)
                }
        }
    }

@StateObject

Objects (structs) get destroyed and rerendered all the time. @StateObject signifies that this data should be kept during re-renders.

This is going to stay alive, while the parent View will be destroyed and created.

Listening to state changes

final class FrameworkGridViewModel: ObservableObject {
    var selectedFramework: Framework? {
        didSet {
            isShowingDetailView = true
        }
    }
 
    @Published var isShowingDetailView = false
}

Each component into their own file

Move each component into their own file. That way, you can preview just that component and debug it.

Modifiers

Every time you add a modifier, you wrap all existing modifiers in a new View. So the order matters.

Like in CSS, children inherit modifieres from parents. These are called “Environment modifiers”.

Viewbuilder

For example, a ZStack or a VStack. There are only specific things you can write within a Viewbuilder.

View performance

Views are structs. They don’t inherit, so creating and destroying them is fast.

The Views are broken out into a View tree. The diff-ing algorithm only changes what is bound reactively.

Basic NavigationView

    var body: some View {
        NavigationView {
            ScrollView {
                LazyVGrid(columns: columns) {
                    ForEach(MockData.frameworks) { framework in
                        FrameworkTitleView(framework: framework)
                    }
                }
            }.navigationTitle(" Frameworks")
        }
        
    }

Directory structure

/UIKit Components
/Views
	Button/
	View/
/Model
	FrameworkData.swift
/Screens
	FrameworkDetailView/
		FrameworkDetailView.swift
	FrameworkGridView/
		FrameworkGridView.swift
		FrameworkGridViewModel.swift