SwiftUI
up:: Swift ⚐
My notes
- SwiftUI Array methods
- SwiftUI Singleton
- SwiftUI Unit tests
- SwiftData
- SwiftUI font sizes
- SwiftUI snippets
- SwiftData in Widgets
- MVVM
- Swift Hashable
Links
-
Data
-
Second app: 00:27min
-
alessiorubicini/SFSymbolsPickerForSwiftUI: A SwiftUI view for selecting SF symbols in your app
-
Choosing the Right SwiftUI Property Wrapper for You | by Alessio Rubicini | Medium
Loose notes
SwiftUI fundamentals course
Course: https://youtu.be/b1oC7sLIgpI?feature=shared&t=18755
- Stacks
- Horizontal/Vertical:
HStack
,VStack
- Background/Foreground:
ZStack
- Horizontal/Vertical:
- Modifiers wrap a View in another View. So the order of modifiers matters.
- Like wrapping an element in
div
s
- Like wrapping an element in
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.
NavigationStack
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 (struct
s) 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 struct
s. 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