Как создать редактируемое текстовое поле в SwiftUI

До iOS 14 SwiftUI все еще нуждалась в поддержке UITextView из UIKit для создания редактируемого текстового поля. Затем жизнь стала лучше в iOS 14, когда Apple выпустила новое представление под названием TextEditor в среде SwiftUI. Это позволяет разработчикам создавать редактируемые многострочные текстовые поля без хлопот, связанных с использованием UIViewRepresentable.
В этом руководстве мы рассмотрим, как работать с TextEditor в вашем приложении SwiftUI. Прежде чем мы начнем, убедитесь, что для практики открыт новый проект. Вы можете использовать эту ссылку, если вам нужен пошаговый процесс, как это сделать.
Этот туториал является частью моей серии SwiftUI Tutorial.
Как сделать текстовый редактор
Создать TextEditor легко. По сути, требуется только переменная состояние для хранения входной строки, а затем передача привязки в TextEditor. Ниже код показывает, как это в основном работает:
struct ContentView: View {
@State private var inputText = ""
var body: some View {
TextEditor(text: $inputText)
}
}
Запустите приложение и попробуйте набрать много текста. Да, я знаю, что приложение выглядит хромым. Итак, давайте как-нибудь сделаем так, чтобы это выглядело презентабельно:
struct ContentView: View {
@State private var inputText = ""
var body: some View {
ZStack {
Color.blue
.ignoresSafeArea(.all)
VStack {
Text("Write down your thoughts")
.font(.title3)
.foregroundColor(.white)
TextEditor(text: $inputText)
} //VStack
} //ZStack
} //body
} //ContentView
Запустите приложение еще раз, и оно будет выглядеть так:

Настройка шрифтов
TextEditor можно настроить (стиль шрифта, цвет и т. д.) так же, как TextView. В приведенном ниже примере мы меняем шрифт и настраиваем lineSpacing.
TextEditor(text: $inputText)
.font(.custom("Futura", size: 20))
.lineSpacing(10)
.foregroundColor(.blue)
Ниже приведен вывод:

Автоматическая замена строчных букв заглавными
По умолчанию для автокапитализации установлено значение .предложения. Но вы можете легко изменить его поведение. Ниже приведены основные варианты в зависимости от того, как вы хотите, чтобы TextEditor вел себя.
- none — без автоматического использования заглавных букв.
- слова — первая буква каждого слова автоматически становится заглавной.
- allCharacters — все символы автоматически начинаются с заглавных букв.
- предложения — первая буква каждого предложения автоматически становится заглавной.
Допустим, вы хотите, чтобы каждое набранное слово автоматически писалось с заглавной буквы.
TextEditor(text: $inputText)
.font(.custom("Futura", size: 20))
.autocapitalization(.words)
Ниже приведен пример вывода:

Отключить автокоррекцию
Автокоррекция часто раздражает. Но хорошо то, что вы можете просто отключить его следующим образом:
TextEditor(text: $inputText)
.font(.custom("Futura", size: 20))
.disableAutocorrection(true)
Инициировать действие с помощью модификатора .onChange
Присоединение модификатора onChange к TextEditor позволяет обнаруживать изменения строки в режиме реального времени. Лучший способ обсудить это дальше — создать простое приложение для создания заметок, которое подсчитывает количество слов в реальном времени. На рисунке 5 ниже показано, как это будет выглядеть.

Для этой практики мы напишем все внутри ContentView. Начиная с переменных. Нам понадобится 2: первый обрабатывает ввод текста, а второй обрабатывает количество слов. Запишите это внутри ContentView:
@State private var inputText: String = "" @State private var wordCounter: Int = 0
Прежде чем кодировать функциональность приложения. Давайте сначала позаботимся о пользовательском интерфейсе и текстовом редакторе, чтобы не перегружать наши мозги. Напишите этот код внутри ContentView:
var body: some View {
ZStack {
Color.blue
.ignoresSafeArea(.all)
VStack {
Text("Write down your thoughts")
.font(.title3)
.foregroundColor(.white)
Text("")
.font(.title3)
.foregroundColor(.white)
TextEditor(text: $inputText)
.font(.custom("Futura", size: 20))
} //VStack
} //ZStack
} //body
Да, это то же самое, что и первый пример, который мы использовали в этом уроке. Как показано на холсте. Теперь пришло время самой важной части — функциональности. Отредактируйте второе текстовое представление внутри VStack следующим образом:
Text(wordCounter <= 1 ? "\(wordCounter) word" : "\(wordCounter) words")
Так что же делает этот код? Мы хотели, чтобы в представлении Текст просто использовалось слово, если у нас есть только 1 или меньше слов в текстовом редакторе. Затем он изменится на форму множественного числа слова, если уже есть 2 или более слов. Чтобы сделать это возможным с помощью всего одной строки кода, мы использовали здесь тройной оператор, чтобы сделать простой оператор if внутри текстового представления.
Для справки, вот как сейчас должен выглядеть код:

Затем давайте закодируем функцию подсчета слов в реальном времени. Прикрепите модификатор .onChange к TextEditor, затем запишите функциональность внутри. Ниже приведен код:
TextEditor(text: $inputText)
.font(.custom("Futura", size: 20))
.onChange(of: inputText) { newValue in
let words = inputText.split { $0 == " " || $0.isNewline }
self.wordCounter = words.count
}
Мы попросили модификатор onChange специально отслеживать изменения в inputText. Всякий раз, когда происходит изменение, строка будет разделена с использованием пробела « » в качестве разделителя. Затем он будет сохранен в константе с именем words. Все разделенные элементы подсчитываются и сохраняются в переменной wordCounter.
Ниже приведен скриншот исходного кода для справки:

Запустите приложение и попробуйте ввести в TextEditor. Наше приложение теперь может подсчитывать все слова в режиме реального времени. Похлопайте себя по спине за хорошо выполненную работу.
Я загрузил исходный код в github. Просто нажмите на эту ссылку.
Да пребудет с вами код,
-Дуга