Swift dynamically create editable modal from Stepper component?
Problem Description:
I have a Stepper component that corresponds to number of people (for now, I don’t want to restrict what the stepper goes up to, but users will likely never enter more than 10). I want to dynamically generate a box that is essentially a Person object/class based on the current value of Stepper.
Current code
struct ContentView: View {
@State private var numPeople = 0
var body: some View {
VStack {
Text("Enter number of people below:")
Stepper("(numPeople.formatted()) People", value: $numPeople)
}
}
Desired outcome if user clicks plus button until the number 3.
Should this be done using a for loop (or ForEach loop)? Should a component other than Stepper be used?
Solution – 1
There are a few different ways of doing this but for growth sake you can consider a PersonModel
and basing the stepper on the count
of Array<PersonModel>
using a computed variable that adds and removes from the array.
import SwiftUI
struct PersonModel: Identifiable{
let id: UUID = .init()
let name: String
}
class PersonVM: ObservableObject{
@Published var people: [PersonModel] = []
var personCount: Int{
get{
//Single source of truth.
people.count
}
set{
let diff: Int = people.count - newValue
if diff == 0{
//No change
} else if diff < 0 { //Add the difference
let new: [PersonModel] = (0..<abs(diff)).map{ n in
PersonModel(name: "Person (people.count + n + 1)")
}
people.append(contentsOf: new)
} else if !people.isEmpty{ //Remove the difference if the array isn't empty
people.removeLast(diff)
}
}
}
}
@available(iOS 15.0, *)
struct PersonView: View {
@StateObject private var vm: PersonVM = .init()
var body: some View {
ScrollView {
Text("Enter number of people below:")
Stepper("(vm.people.count.formatted()) People", value: $vm.personCount, in: 0...10, step: 1)
ForEach(vm.people) { person in
ZStack{
Color.blue
Text(person.name)
.foregroundColor(.white)
}.padding(2)
}
}
}
}