SwiftUI — получение текстового поля в массив в ForEach

#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)
            }
        }
    }
}
  

}