我有一个文本字段,用户可以在其中手动输入位置字符串。这与我观察到的对象
AppState
绑定,我已将其重新标记为 (app
),其中有一个名为 @Published var
的 destination
。这工作正常,我可以在文本字段中绑定手动输入的文本,如下所示:
TextField("Destination", text: $app.destination)
我已经开始尝试实现一个收藏夹系统,用户可以保存和更改最多 4 个目的地,以便快速输入而无需重新键入(一次只能在文本字段中输入 1 个目的地)。
当用户按下他们最喜欢的内容之一时,最喜欢的内容会出现在文本字段中,他们可以通过输入新内容并保存来更改它,或者按新的最爱来替换文本字段中的内容。用户还必须可以选择根本不输入收藏夹,并且也能够输入随机收藏夹。
到目前为止,我已经让这部分工作得相当好,并且对功能感到满意。
我的问题是,我不知道如何将文本字段中的任何内容绑定到我的
ObservedObject
app.destination
。经过一番故障排除后,我发现只有手动输入的文本才会存储在app.destination
中。在文本字段中出现最喜欢的内容不会绑定。
我尝试过
.onChange()
和 .onTapGesture()
和 .focused()
的变体来运行 if/else 块,该块会简单地将文本字段中的文本分配给 app.destination
,但它仍然有错误,您无法保存新的最爱...
我正在绕圈试图解决这个问题,非常感谢一些帮助。
我有一个最小的可复制示例供您复制和粘贴。谢谢你
主视图
struct ContentView: View {
@StateObject private var favoritesViewModel = FavoritesViewModel()
@ObservedObject var app = AppState()
@State private var newLocation = ""
@State private var selectedLocationIndex = 0
@State private var userSelectedFavourite: String = ""
@State private var favouritePressed: Bool = false
@FocusState private var isFocused: Bool
var body: some View {
VStack {
HStack {
//.........THIS IS THE ISSUE TEXTFIELD
TextField("Destination", text: (favouritePressed && !isFocused) ? $favoritesViewModel.favoriteLocations[selectedLocationIndex] : $newLocation)
//.....................................
.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])
.tag(index)
}
}
.onChange(of: selectedLocationIndex) {
favouritePressed = true
isFocused = false
}
.pickerStyle(.palette)
Spacer()
}
.navigationTitle("Favorite Locations")
}
func saveLocation(locationIndex: Int) {
print("Saving...")
if !newLocation.isEmpty {
favoritesViewModel.addFavoriteLocation(newLocation, locationIndex: locationIndex)
newLocation = ""
}
}
}
这个只存储收藏夹:
class FavoritesViewModel: ObservableObject {
// Key for UserDefaults
let favoritesKey = "favoriteLocations"
// UserDefaults instance
var defaults: UserDefaults {
UserDefaults.standard
}
// Published property to manage favorite locations
@Published var favoriteLocations: [String] = []
// Initialize with default values
init() {
self.favoriteLocations = loadFavorites()
}
// Load favorite locations from UserDefaults
func loadFavorites() -> [String] {
return defaults.stringArray(forKey: favoritesKey) ?? []
}
// Save favorite locations to UserDefaults
func saveFavorites() {
defaults.set(favoriteLocations, forKey: favoritesKey)
}
// Add a new favorite location
func addFavoriteLocation(_ location: String, locationIndex: Int) {
// Check if location is already in favorites and limit to 4 locations
if !favoriteLocations.contains(location) {
if favoriteLocations.count < 4 {
favoriteLocations.insert(location, at: locationIndex)
} else {
favoriteLocations.remove(at: locationIndex)
favoriteLocations.insert(location, at: locationIndex)
}
saveFavorites() // Save after adding or updating favorites
}
}
}
还有 Observed 类:
class AppState: ObservableObject {
// THIS IS THE VARIABLE IM TRYING TO SAVE TEXT TO
@Published var destination: String = ""
}
您仍应使用
$app.destination
作为文本字段的绑定。请记住,单一事实来源。
当用户在选择器中选择某些内容时,只需将
app.destination
设置为所选位置即可。
您只需要这些状态:
@StateObject private var favoritesViewModel = FavoritesViewModel()
@StateObject private var app = AppState()
@State private var selectedLocationIndex: Int?
@FocusState private var isFocused: Bool
我认为
selectedLocationIndex
是可选的更有意义,代表不选择任何东西的状态。
其余代码很简单。请注意如何在
app.destination
中设置 .onChange(of: selectedLocationIndex)
。
var body: some View {
VStack {
HStack {
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 ?? 0)
}
}
Picker("Favorite Locations", selection: $selectedLocationIndex) {
ForEach(favoritesViewModel.favoriteLocations.indices, id: \.self) { index in
Text(favoritesViewModel.favoriteLocations[index]).tag(Optional.some(index))
}
}
.onChange(of: selectedLocationIndex) { _, newValue in
if let newValue {
isFocused = false
app.destination = favoritesViewModel.favoriteLocations[newValue]
}
}
.pickerStyle(.palette)
Spacer()
}
}
func saveLocation(locationIndex: Int) {
print("Saving...")
favoritesViewModel.addFavoriteLocation(app.destination, locationIndex: locationIndex)
app.destination = ""
}