Как создать многострочное TextField в SwiftUI?

Я пытался создать многострочное TextField в SwiftUI, но я не могу понять, как.

Вот код, который у меня сейчас есть:

struct EditorTextView : View {
    @Binding var text: String

    var body: some View {
        TextField($text)
            .lineLimit(4)
            .multilineTextAlignment(.leading)
            .frame(minWidth: 100, maxWidth: 200, minHeight: 100, maxHeight: .infinity, alignment: .topLeading)
    }
}

#if DEBUG
let sampleText = """
Very long line 1
Very long line 2
Very long line 3
Very long line 4
"""

struct EditorTextView_Previews : PreviewProvider {
    static var previews: some View {
        EditorTextView(text: .constant(sampleText))
            .previewLayout(.fixed(width: 200, height: 200))
    }
}
#endif

Но это вывод:

enter image description here

Ответ 1

Обновление: хотя Xcode11 beta 4 теперь поддерживает TextView, я обнаружил, что перенос UITextView по-прежнему является лучшим способом заставить работать редактируемый многострочный текст. Например, TextView имеет проблемы с отображением, когда текст не отображается должным образом внутри представления.

Оригинальный (бета 1) ответ:

На данный момент вы можете обернуть UITextView для создания компонуемого View:

import SwiftUI
import Combine

final class UserData: BindableObject  {
    let didChange = PassthroughSubject<UserData, Never>()

    var text = "" {
        didSet {
            didChange.send(self)
        }
    }

    init(text: String) {
        self.text = text
    }
}

struct MultilineTextView: UIViewRepresentable {
    @Binding var text: String

    func makeUIView(context: Context) -> UITextView {
        let view = UITextView()
        view.isScrollEnabled = true
        view.isEditable = true
        view.isUserInteractionEnabled = true
        return view
    }

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

struct ContentView : View {
    @State private var selection = 0
    @EnvironmentObject var userData: UserData

    var body: some View {
        TabbedView(selection: $selection){
            MultilineTextView(text: $userData.text)
                .tabItemLabel(Image("first"))
                .tag(0)
            Text("Second View")
                .font(.title)
                .tabItemLabel(Image("second"))
                .tag(1)
        }
    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(UserData(
                text: """
                        Some longer text here
                        that spans a few lines
                        and runs on.
                        """
            ))

    }
}
#endif

enter image description here

Ответ 2

С помощью Text() вы можете добиться этого, используя .lineLimit(nil), и документация предполагает, что это должно работать и для TextField(). Тем не менее, я могу подтвердить, что в настоящее время это работает не так, как ожидалось.

Я подозреваю ошибку - рекомендую заполнить отчет с помощью Feedback Assistant. Я сделал это, и идентификатор FB6124711.

Ответ 3

Я только что попытался создать многострочное текстовое поле с помощью swiftui в GM-версии Xcode версии 11.0 (11A419c), используя lineLimit(). Это все еще не работает. Я не могу поверить, что Apple еще не исправила это. Многострочное текстовое поле довольно часто встречается в мобильных приложениях.

Ответ 4

Это оборачивает UITextView в бета 6 Xcode версии 11.0 (все еще работает на Xcode 11 GM seed 2):

import SwiftUI

struct ContentView: View {
     @State var text = ""

       var body: some View {
        VStack {
            Text("text is: \(text)")
            TextView(
                text: $text
            )
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
        }

       }
}

struct TextView: UIViewRepresentable {
    @Binding var text: String

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

    func makeUIView(context: Context) -> UITextView {

        let myTextView = UITextView()
        myTextView.delegate = context.coordinator

        myTextView.font = UIFont(name: "HelveticaNeue", size: 15)
        myTextView.isScrollEnabled = true
        myTextView.isEditable = true
        myTextView.isUserInteractionEnabled = true
        myTextView.backgroundColor = UIColor(white: 0.0, alpha: 0.05)

        return myTextView
    }

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

    class Coordinator : NSObject, UITextViewDelegate {

        var parent: TextView

        init(_ uiTextView: TextView) {
            self.parent = uiTextView
        }

        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            return true
        }

        func textViewDidChange(_ textView: UITextView) {
            print("text now: \(String(describing: textView.text!))")
            self.parent.text = textView.text
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Ответ 5

Привет @gabriellanata, если вы хотите показывать только многострочный текст, используйте UILabel и вы хотите добавлять или редактировать текст после запуска приложения, вы можете использовать UITextView.