#foreach #binding #swiftui
#foreach #привязка #swiftui
Вопрос:
Цель состоит в том, чтобы иметь TextField
который принимает символы по мере их ввода и отображает их под TextField
в «куче». Под кучкой я подразумеваю, что каждый новый символ отображается поверх предыдущего. Сложить буквы достаточно просто — я использую ForEach
для перебора массива внутри ZStack
. Чтобы получить символы в массиве, я использовал пользовательскую привязку. Это работает, но проблема в том, что символы повторяются каждый раз, когда вводится новый символ. Например, если пользователь вводит CAT, сначала появится C, затем CA поверх C, затем CAT поверх CA и C. Другими словами, есть шесть символов, сложенных, когда я хотел только три.
struct ContentView: View {
@State private var letter = ""
@State private var letterArray = [String]()
var body: some View {
let binding = Binding<String>(
get: { self.letter },
set: { self.letter = $0
self.letterArray.append(self.letter)
})
return VStack {
TextField("Type letters and numbers", text: binding)
ZStack {
ForEach(letterArray, id: .self) { letter in
Text(letter)
}
}
}
}
}
Обновить:
Я делал проблему немного сложнее, чем она была. С помощью ObservableObject
я смог отделить логику от представления И упростить код. Сначала я создал модель представления. Теперь, каждый раз, когда пользователь вводит что-либо в TextField
, это перехватывается didSet
и преобразуется в массив символов. Обратите внимание, мне пришлось использовать map для преобразования из массива символов в массив строк, потому что ForEach
не работает с символами.
class ViewModel: ObservableObject {
@Published var letterArray = [String]()
@Published var letter = "" {
didSet {
letterArray = Array(letter).map { String($0) }
}
}
}
В contentView мне нужно только @ObservedObject var vm = ViewModel()
Затем я ссылаюсь на переменные, используя vm.letter
или vm.letterArray
Ответ №1:
В верхней части города, где я получаю вашу проблему, может ли приведенный ниже код помочь вам, я изменил ваш код, как показано ниже;
struct ContentView: View {
@State private var letter = ""
@State private var letterCounter = 0
@State private var letterArray = [String]()
var body: some View {
let binding = Binding<String>(
get: { self.letter },
set: { self.letter = $0
if self.letter.count > self.letterCounter {
if let lastLetter = self.letter.last{
self.letterArray.append(String(lastLetter))
}
}else{
_ = self.letterArray.removeLast()
}
self.letterCounter = self.letter.count
})
return VStack {
TextField("Type letters and numbers", text: binding)
VStack {
ForEach(letterArray, id: .self) { letter in
Text(letter)
}
}
}
}
}