Apple’s Reminders app reveals additional editing controls based on the user’s current focus. I wanted to reproduce this behaviour in SwiftUI.
I will start with a List
of Task
models.
TaskList.swift
:
List {
ForEach(tasks) { task in
TaskView(task: task)
}
Then I’ll set up TaskView
with some state for each of the Task
model’s fields
TaskView.swift
:
struct TaskView: View {
var task:Task
@State private var title:String
@State private var notes:String
init(task: Task) {
self.task = task
_title = .init(initialValue: task.title ?? "")
_notes = .init(initialValue: task.notes ?? "")
}
var body: some View {
HStack{
VStack(alignment: .leading){
TextField("Title", text: $title)
.foregroundStyle(.primary)
Text((try? AttributedString(markdown: notes)) ?? "")
.foregroundStyle(.secondary)
}
}
.padding()
}
}
This is enough to make each task editable (I’ll skip the storage part today).
Note that I’m using Swift’s new Markdown support for my notes field, using AttributedString(markdown: notes)
.
I’m also using the new foregroundStyle
.primary
and .secondary
options for my text formatting instead of using plain colour values.
Then we just create a private enum called Field
and an accompanying @FocusState
variable as per this video.
private enum Field: Int, Hashable{
case title, notes
}
@FocusState private var focusedField: Field?
Now we have a focusedField
variable that we can look at for the current focus state. This lets us dynamically toggle form controls when any field in a particular TaskView
has focus.
VStack(alignment: .leading){
TextField("Title", text: $title)
.foregroundStyle(.primary)
.focused($focusedField, equals: .title)
if focusedField == nil {
Text((try? AttributedString(markdown: notes)) ?? "")
.foregroundStyle(.secondary)
}else{
TextField("Notes", text: $notes)
.focused($focusedField, equals: .notes)
HStack{
Button(action: {}){
Text("Add Location")
}.buttonStyle(.bordered)
}
}
}
Now when one of the fields is focused, the “Add Location” button is visible.
I’m not sure this would have been possible in previous versions of SwiftUI without using a UIKit control wrapper! @FocusState
is a welcome new feature.
Next step, figure out how to focus a row in the list when it is first added…