You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中动态创建的TextField如何在外部视图获取输入值?

解决方案

问题根源在于你的Input视图使用@State存储输入值,这是子视图的局部状态,无法与外部数据源双向同步。要实现外部视图获取输入值,需要通过状态提升+双向绑定来解决,具体步骤如下:

1. 修改Input视图,使用@Binding替代@State

将子视图的局部状态改为从外部传入的绑定,确保输入值能同步回父视图:

struct Input: View {
    
    var title: String
    @Binding var value: String // 替换@State为@Binding,实现双向绑定
    var disableInputMode: Bool = true

    var body: some View {                
        VStack {
            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundColor(Color("SecondaryTextColor"))
            TextField("", text: $value)
                .disabled(disableInputMode)
                .frame(maxWidth: .infinity, alignment: .leading)
            Divider()
        }
        .padding()        
    }
}

2. 确保数据源支持双向绑定

根据你的数据模型类型,选择对应的实现方式:

情况一:数据模型为struct(推荐)

如果你的DetailDatum是值类型,需要让它遵循Identifiable,并在ViewModel中用@Published维护可变数组:

// 定义数据模型
struct DetailDatum: Identifiable {
    let id = UUID()
    var title: String
    var detail: String // 改为非可选类型,避免强制解包
}

// 定义ViewModel
class DetailsViewModel: ObservableObject {
    @Published var details: [DetailDatum] = [] // @Published自动通知视图更新
}

然后在父视图中,通过ForEach的绑定形式传递数据:

@ObservedObject var detailsViewModel: DetailsViewModel // 或@StateObject(iOS 14+)

ScrollView {
    VStack {
        // 使用$绑定数组元素,直接传递detail的绑定给Input
        ForEach($detailsViewModel.details) { $datum in
            Input(title: datum.title, value: $datum.detail)
        }
    }.frame(maxWidth: .infinity)
    .padding()
}.background(Color("Light"))
.cornerRadius(25)
.padding()

情况二:数据模型为class

如果你的DetailDatum是引用类型,让它遵循ObservableObject并使用@Published标记detail属性:

// 定义数据模型
class DetailDatum: Identifiable, ObservableObject {
    let id = UUID()
    var title: String
    @Published var detail: String // @Published监听属性变化

    init(title: String, detail: String) {
        self.title = title
        self.detail = detail
    }
}

// 定义ViewModel
class DetailsViewModel: ObservableObject {
    @Published var details: [DetailDatum] = []
}

父视图中传递绑定的方式略有不同:

@ObservedObject var detailsViewModel: DetailsViewModel

ScrollView {
    VStack {
        ForEach(detailsViewModel.details) { datum in
            // 通过datum.$detail获取绑定
            Input(title: datum.title, value: datum.$detail)
        }
    }.frame(maxWidth: .infinity)
    .padding()
}.background(Color("Light"))
.cornerRadius(25)
.padding()

3. 关键注意事项

  • 避免使用datum.detail!强制解包,建议将模型中的detail设为非可选类型,初始值为空字符串,防止运行时崩溃。
  • 确保ViewModel被正确注入到父视图中(如通过@ObservedObject或@StateObject),否则数据变化无法触发视图更新。

内容的提问来源于stack exchange,提问作者Ron Weasley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 06:25:17