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
相关产品推荐
相关产品推荐

