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

SwiftUI中TextField绑定与收藏功能共存的实现问题

问题根源

你当前的TextField采用条件绑定,要么关联收藏数组的元素,要么关联临时变量newLocation,完全没和app.destination建立稳定绑定,导致收藏选中的内容无法同步到这个属性。同时冗余的状态变量(favouritePressed、newLocation)反而增加了逻辑复杂度,引发同步bug。

解决方案

核心思路是让TextField始终绑定到app.destination,所有输入/选择操作都围绕这个属性展开,收藏选择时直接赋值给它,保存时用它的值更新收藏列表。

修改后的代码:

1. 主视图(ContentView)
struct ContentView: View {
    @StateObject private var favoritesViewModel = FavoritesViewModel()
    @ObservedObject var app = AppState()
    @State private var selectedLocationIndex = 0
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack {
            HStack {
                // 始终绑定到app.destination,统一数据源
                TextField("Destination", text: $app.destination)
                    .focused($isFocused)
                    .contentShape(.rect)
                    .textInputAutocapitalization(.characters)
                    .disableAutocorrection(true)
                    .padding()
                    .frame(width: 280, height: 60)
                    .overlay(
                        RoundedRectangle(cornerRadius: 10)
                            .stroke(Color.gray, lineWidth: 2)
                    )
                
                Button("Save") {
                    saveLocation(locationIndex: selectedLocationIndex)
                }
            }
            
            Picker("Favorite Locations", selection: $selectedLocationIndex) {
                ForEach(favoritesViewModel.favoriteLocations.indices, id: \.self) { index in
                    Text(favoritesViewModel.favoriteLocations[index].isEmpty ? "未设置" : favoritesViewModel.favoriteLocations[index])
                        .tag(index)
                }
            }
            .onChange(of: selectedLocationIndex) { _ in
                // 选中收藏项时,将对应值赋值给app.destination
                app.destination = favoritesViewModel.favoriteLocations[selectedLocationIndex]
                isFocused = false
            }
            .pickerStyle(.palette)

            Spacer()
        }
        .navigationTitle("Favorite Locations")
    }
    
    func saveLocation(locationIndex: Int) {
        guard !app.destination.isEmpty else { return }
        favoritesViewModel.addFavoriteLocation(app.destination, locationIndex: locationIndex)
        app.destination = "" // 保存后清空输入框,可选操作
    }
}
2. 收藏管理类(FavoritesViewModel)

初始化时默认创建4个空元素,保证Picker始终有4个可选位置(符合最多4个收藏的需求):

class FavoritesViewModel: ObservableObject {
    let favoritesKey = "favoriteLocations"
    var defaults: UserDefaults { UserDefaults.standard }
    @Published var favoriteLocations: [String] = []

    init() {
        let saved = loadFavorites()
        // 确保数组始终有4个元素,不足则补空
        self.favoriteLocations = saved.count < 4 ? saved + Array(repeating: "", count: 4 - saved.count) : saved.prefix(4).map { $0 }
        saveFavorites() // 初始化时同步到UserDefaults
    }

    func loadFavorites() -> [String] {
        defaults.stringArray(forKey: favoritesKey) ?? []
    }

    func saveFavorites() {
        defaults.set(favoriteLocations, forKey: favoritesKey)
    }

    func addFavoriteLocation(_ location: String, locationIndex: Int) {
        // 直接替换对应位置的元素,无需判断数量(已固定4个)
        guard locationIndex < favoriteLocations.count else { return }
        favoriteLocations[locationIndex] = location
        saveFavorites()
    }
}
3. AppState保持不变
class AppState: ObservableObject {
    @Published var destination: String = ""
}

关键修改点说明

  • 移除了newLocation、favouritePressed等冗余状态,简化逻辑
  • TextField固定绑定$app.destination,不管手动输入还是收藏选择,内容都会同步到这个属性
  • Picker选中时直接将收藏值赋值给app.destination,实现内容填充
  • 收藏列表初始化时固定为4个元素,避免Picker无选项的问题,保存时直接替换对应位置的值,逻辑更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 18:34:59