Привязка внутри детали NavigationSplitView (TextField, TextEditor)
Я использую двухколоночныйNavigationSplitView
. Попытка выяснить, как обновить модель данных через.onSubmit
модификатор и использовать представление безBinding.constant
.
В рамкахdetail
раздел, у меня естьTextField
иTextEditor
.
- Как избежать
Binding.contant()
? Я имею в виду, мне нужна мутация. - Это правильный способ обновления
value
собственность в модели?
Мне нужен один выбор в списке.
Вот мой пример кода (70 строк):
struct Model: Identifiable, Hashable {
var id = UUID()
var title: String = "Brand new"
var value: String = ""
func updateValue() async -> Model {
return Model(id: id, title: title, value: "The boar is running through the field happily")
}
}
final class DataModel: ObservableObject {
@Published
var models: [Model] = [
.init(title: "First", value: "fur"),
.init(title: "Second", value: "meow"),
.init(title: "Another", value: "Make SwiftUI, not war")
]
@MainActor
func updateModel(for model: Model.ID) async -> Void {
var findModel = models.first { $0.id == model }
findModel = await findModel?.updateValue()
}
}
struct ModelView: View {
@StateObject
private var dataModel = DataModel()
@State
private var listSelection: Model.ID?
private var selectedModel: Model? {
guard let selection = listSelection else { return nil }
return dataModel.models.first { $0.id == selection }
}
var body: some View {
NavigationSplitView {
List(dataModel.models, selection: $listSelection) { model in
NavigationLink(model.title, value: model.id)
}
} detail: {
if let selectedModel {
VStack {
TextField("Title", text: .constant(selectedModel.title))
.padding()
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 20))
.submitLabel(.go)
.onSubmit {
Task {
// Update Model.value by hit `Go`
await dataModel.updateModel(for: selectedModel.id)
}
}
TextEditor(text: .constant(selectedModel.value))
}
.padding()
.navigationTitle(selectedModel.title)
}
}
}
}
struct ModelView_Previews: PreviewProvider {
static var previews: some View {
ModelView()
.colorScheme(.light)
}
}
1 ответ
Через пару дней я понял, что я могу сделать. Никто не ответил на вопрос, поэтому я решил проблему таким образом.
Окончательное решение ниже:
struct Model: Identifiable, Hashable {
var id = UUID()
var title: String = "Brand new"
var value: String = ""
func updateValue() async -> Model {
return Model(id: id, title: title, value: "The boar is running through the field happily")
}
}
final class DataModel: ObservableObject {
@Published
var models: [Model] = [
.init(title: "First", value: "fur"),
.init(title: "Second", value: "meow"),
.init(title: "Another", value: "Make SwiftUI, not war")
]
@MainActor
func updateModel(for model: Binding<Model>) async -> Void {
model.wrappedValue = await model.wrappedValue.updateValue()
}
func bindingToModel(_ model: Model.ID) -> Binding<Model> {
Binding<Model> {
guard let index = self.models.firstIndex(where: { $0.id == model }) else {
return Model()
}
return self.models[index]
} set: { newModel in
guard let index = self.models.firstIndex(where: { $0.id == model }) else { return }
self.models[index] = newModel
}
}
}
struct ModelView: View {
@StateObject
private var dataModel = DataModel()
@State
private var listSelection: Model.ID?
var body: some View {
NavigationSplitView {
List(dataModel.models, selection: $listSelection) { model in
NavigationLink(model.title, value: model.id)
}
} detail: {
if let listSelection, let bindModel = dataModel.bindingToModel(listSelection) {
VStack {
TextField("Title", text: bindModel.title)
.padding()
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 20))
.submitLabel(.go)
.onSubmit {
Task {
// Update Model.value by hit `Go`
await dataModel.updateModel(for: bindModel)
}
}
TextEditor(text: bindModel.value)
}
.padding()
.navigationTitle(bindModel.title)
}
}
}
}