NavigationSplitView详情页TextField/TextEditor绑定与模型更新问题
1. 避免使用Binding.constant(),实现双向数据绑定
Binding.constant()会让输入控件变为只读状态,要实现可编辑功能,需在详情视图中创建临时状态变量绑定输入控件,提交时同步到数据模型:
- 在详情区域的
VStack内部,声明@State变量存储编辑中的标题和内容 - 将
TextField和TextEditor绑定到这些临时变量 - 在
.onSubmit回调中调用模型更新方法,把临时变量的值同步回数据源
2. 修正Model.value的更新逻辑
当前updateModel方法仅修改了局部变量,未更新dataModel.models数组中的元素,需找到目标模型的索引并替换:
- 在
DataModel的updateModel方法中,先定位目标模型在数组中的索引 - 调用更新方法获取新模型,替换数组对应位置的元素
- 若需支持自定义输入内容更新,可修改
updateValue方法接收参数,直接使用临时变量的值更新
3. 实现列表单选功能
当前代码的List(selection: $listSelection)已支持单选,只需确保:
listSelection声明为@State private var listSelection: Model.ID?(可选类型默认支持单选)NavigationLink的value绑定到model.id,与List的selection类型匹配
修改后的完整代码
struct Model: Identifiable, Hashable { var id = UUID() var title: String = "Brand new" var value: String = "" // 支持自定义内容更新的方法 func updateValue(with newValue: String) -> Model { Model(id: id, title: title, value: newValue) } // 保留原有示例的固定更新逻辑(可选) func updateValue() -> Model { 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 modelId: Model.ID, withTitle newTitle: String, newValue: String) { guard let index = models.firstIndex(where: { $0.id == modelId }) else { return } models[index] = models[index].updateValue(with: newValue) models[index].title = newTitle } // 保留原有示例的固定更新方法(可选) @MainActor func updateModel(for modelId: Model.ID) { guard let index = models.firstIndex(where: { $0.id == modelId }) else { return } models[index] = models[index].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 } 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 { @State var editedTitle = selectedModel.title @State var editedValue = selectedModel.value VStack { TextField("Title", text: $editedTitle) .padding() .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 20)) .submitLabel(.go) .onSubmit { dataModel.updateModel(for: selectedModel.id, withTitle: editedTitle, newValue: editedValue) } TextEditor(text: $editedValue) .padding() .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 20)) } .padding() .navigationTitle(selectedModel.title) .onChange(of: selectedModel) { newModel in editedTitle = newModel?.title ?? "" editedValue = newModel?.value ?? "" } } else { Text("请选择一个项目") .navigationTitle("无选择") } } } } struct ModelView_Previews: PreviewProvider { static var previews: some View { ModelView() .colorScheme(.light) } }
内容的提问来源于stack exchange,提问作者Nick Rossik
相关产品推荐
相关产品推荐

