SwiftUI UIViewRepresentable UITextView Binding - PullRequest
1 голос
/ 21 января 2020

Многострочный ввод текста в настоящее время не поддерживается в SwiftUI (надеюсь, эта функция будет добавлена ​​в ближайшее время!), Поэтому я пытался использовать интегрированную среду для реализации UITextView из UIKit, который поддерживает многострочный ввод, однако я был со смешанными результатами.

Это код, который я создал для создания текстового представления:

struct MultilineTextView: UIViewRepresentable {

    @Binding var text: String


    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.isScrollEnabled = true
        view.isEditable = true
        view.isUserInteractionEnabled = true
        view.backgroundColor = UIColor.white
        view.textColor = UIColor.black
        view.font = UIFont.systemFont(ofSize: 17)
        view.delegate = context.coordinator
        return view
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
    }

    func frame(numLines: CGFloat) -> some View {
        let height = UIFont.systemFont(ofSize: 17).lineHeight * numLines
        return self.frame(height: height)
    }

    func makeCoordinator() -> MultilineTextView.Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UITextViewDelegate {
        var parent: MultilineTextView

        init(_ parent: MultilineTextView) {
            self.parent = parent
        }

        func textViewDidChange(_ textView: UITextView) {
            parent.text = textView.text
        }
    }
}

Затем я реализовал его в представлении swiftUI, например:

MultilineTextView(text: title ? $currentItem.titleEnglish : $currentItem.pairArray[currentPair].english)//.frame(numLines: 4)

И привязал его к переменной состояния:

@State var currentItem:Item

Это вроде работает. Однако состояние var currentItem: Item содержит массив строк, которые я затем циклически перебираю, используя кнопки, которые обновляют массив строк на основе того, что было введено в MultilineTextView. Это где я сталкиваюсь с проблемой, когда MultilineTextView, кажется, связывает только первый элемент строки в массиве, и тогда он не изменится. Когда я использую родное представление TextField в swiftUI, эта функция работает нормально, и я могу циклически перемещаться по массиву строк и обновлять его, вводя текст в TextField.

Я думаю, что я должен что-то упустить в структуре MultilineTextView, чтобы разрешить эту функцию , Любые указатели принимаются с благодарностью.

Обновление: Добавлены структуры моделей

struct Item: Identifiable, Codable {
    let id = UUID()
    var completed = false
    var pairArray:[TextPair]
}

struct TextPair: Identifiable, Codable {
    let id = UUID()
    var textOne:String
    var textTwo:String
}

Редактировать: Так что я сделал еще несколько копаний, и я нашел то, что я считаю проблемой. Когда textViewDidChange UITextView запускается, он отправляет обновленный текст, который я вижу в консоли. Странно то, что функция updateUIView также запускается и обновляет текст UITextView с тем, что было в привязке var, до того как обновление было отправлено через textViewDidChange. В результате UITextview просто отказывается измениться, когда вы вводите его. Странно то, что он работает для первой строки в массиве, но при изменении элемента он больше не работает.

Ответы [ 2 ]

1 голос
/ 22 января 2020

Похоже, что SwiftUI создает два варианта UIViewRepresentable для каждой привязки, но не переключает их при изменении состояния, ie title ... возможно, из-за дефекта, который стоит отправить в Apple.

Я нашел отработанный обходной путь (протестировано с Xcode 11.2 / iOS 13.2), вместо этого используйте явно разные представления, как показано ниже

if title {
    MultilineTextView(text: $currentItem.titleEnglish)
} else {
    MultilineTextView(text: $currentItem.pairArray[currentPair].textOne)
}
0 голосов
/ 30 января 2020

Итак, я выяснил проблему в конце, причина, по которой она не обновлялась, заключалась в том, что я передавал строку, которая была расположена с двумя переменными состояния. Вы можете видеть, что в следующей строке currentItem - это одна переменная состояния, а currentPair - другая переменная состояния, которая предоставляет порядковый номер для поиска строки. Последний не обновлялся, потому что он также не передавался в многострочное текстовое представление через привязку.

MultilineTextView(text: title ? $currentItem.titleEnglish : $currentItem.pairArray[currentPair].english)

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

...