SwiftUI'de nasıl çok satırlı bir TextField oluşturabilirim?


93

SwiftUI'de çok satırlı bir TextField oluşturmaya çalışıyorum, ancak nasıl olduğunu anlayamıyorum.

Şu anda sahip olduğum kod bu:

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

Ancak çıktı şu:

görüntü açıklamasını buraya girin


1
Sadece Xcode Sürüm 11.0 (11A419c) GM'de lineLimit () kullanarak swiftui ile çok satırlı bir metin alanı oluşturmaya çalıştım. Hala çalışmıyor. Apple'ın bunu henüz düzeltmediğine inanamıyorum. Çok satırlı bir metin alanı, mobil Uygulamalarda oldukça yaygındır.
e987

Yanıtlar:


49

Güncelleme: Xcode11 beta 4 artık desteklese de TextView, a sarmalamanın UITextView, düzenlenebilir çok satırlı metni çalıştırmak için en iyi yol olduğunu buldum . Örneğin, TextViewmetnin görünümün içinde düzgün görünmediği görüntü hataları var.

Orijinal (beta 1) cevap:

Şimdilik, bir UITextViewoluşturulabilir oluşturmak için a sarmalayabilirsiniz 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

görüntü açıklamasını buraya girin


Harika geçici çözüm! Saf SwiftUI kullanılarak çözülebilene kadar şimdilik kabul ediyorum.
gabriellanata

7
Bu çözüm, içinde halihazırda yeni satırlar olan metni görüntülemenize olanak tanır, ancak doğal olarak uzun satırları kesmiyor / kaydırmıyor gibi görünüyor. (Metin çerçevenin dışında bir satırda yatay olarak büyümeye devam ediyor.) Uzun satırların nasıl sarılacağı hakkında bir fikriniz var mı?
Michael

6
State (bir Publisher ile EnvironmentObject yerine) kullanırsam ve bunu MultilineTextView'a bir bağlama olarak geçirirsem, işe yaramıyor gibi görünüyor. Değişiklikleri Duruma nasıl geri yansıtabilirim?
gri

Bir environmentObject kullanmadan metin görünümünde varsayılan bir metin ayarlamanın herhangi bir yolu var mı?
Learn2Code

83

Tamam, @sas yaklaşımıyla başladım, ancak gerçekten içeriğe uygun çok satırlı metin alanı gibi görünmesine ve hissetmesine ihtiyacım vardı. İşte sahip olduğum şey. Umarım başkası için faydalı olur ... Kullanılmış Xcode 11.1.

Özel MultilineTextField sağlanmıştır:
1. içerik sığdır
2. otomatik odaklama
3. yer tutucu
4. tamamlama

İçeriğe uygun swiftui çok satırlı metin alanının önizlemesi Yer tutucu eklendi

import SwiftUI
import UIKit

fileprivate struct UITextViewWrapper: UIViewRepresentable {
    typealias UIViewType = UITextView

    @Binding var text: String
    @Binding var calculatedHeight: CGFloat
    var onDone: (() -> Void)?

    func makeUIView(context: UIViewRepresentableContext<UITextViewWrapper>) -> UITextView {
        let textField = UITextView()
        textField.delegate = context.coordinator

        textField.isEditable = true
        textField.font = UIFont.preferredFont(forTextStyle: .body)
        textField.isSelectable = true
        textField.isUserInteractionEnabled = true
        textField.isScrollEnabled = false
        textField.backgroundColor = UIColor.clear
        if nil != onDone {
            textField.returnKeyType = .done
        }

        textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        return textField
    }

    func updateUIView(_ uiView: UITextView, context: UIViewRepresentableContext<UITextViewWrapper>) {
        if uiView.text != self.text {
            uiView.text = self.text
        }
        if uiView.window != nil, !uiView.isFirstResponder {
            uiView.becomeFirstResponder()
        }
        UITextViewWrapper.recalculateHeight(view: uiView, result: $calculatedHeight)
    }

    fileprivate static func recalculateHeight(view: UIView, result: Binding<CGFloat>) {
        let newSize = view.sizeThatFits(CGSize(width: view.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
        if result.wrappedValue != newSize.height {
            DispatchQueue.main.async {
                result.wrappedValue = newSize.height // !! must be called asynchronously
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(text: $text, height: $calculatedHeight, onDone: onDone)
    }

    final class Coordinator: NSObject, UITextViewDelegate {
        var text: Binding<String>
        var calculatedHeight: Binding<CGFloat>
        var onDone: (() -> Void)?

        init(text: Binding<String>, height: Binding<CGFloat>, onDone: (() -> Void)? = nil) {
            self.text = text
            self.calculatedHeight = height
            self.onDone = onDone
        }

        func textViewDidChange(_ uiView: UITextView) {
            text.wrappedValue = uiView.text
            UITextViewWrapper.recalculateHeight(view: uiView, result: calculatedHeight)
        }

        func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
            if let onDone = self.onDone, text == "\n" {
                textView.resignFirstResponder()
                onDone()
                return false
            }
            return true
        }
    }

}

struct MultilineTextField: View {

    private var placeholder: String
    private var onCommit: (() -> Void)?

    @Binding private var text: String
    private var internalText: Binding<String> {
        Binding<String>(get: { self.text } ) {
            self.text = $0
            self.showingPlaceholder = $0.isEmpty
        }
    }

    @State private var dynamicHeight: CGFloat = 100
    @State private var showingPlaceholder = false

    init (_ placeholder: String = "", text: Binding<String>, onCommit: (() -> Void)? = nil) {
        self.placeholder = placeholder
        self.onCommit = onCommit
        self._text = text
        self._showingPlaceholder = State<Bool>(initialValue: self.text.isEmpty)
    }

    var body: some View {
        UITextViewWrapper(text: self.internalText, calculatedHeight: $dynamicHeight, onDone: onCommit)
            .frame(minHeight: dynamicHeight, maxHeight: dynamicHeight)
            .background(placeholderView, alignment: .topLeading)
    }

    var placeholderView: some View {
        Group {
            if showingPlaceholder {
                Text(placeholder).foregroundColor(.gray)
                    .padding(.leading, 4)
                    .padding(.top, 8)
            }
        }
    }
}

#if DEBUG
struct MultilineTextField_Previews: PreviewProvider {
    static var test:String = ""//some very very very long description string to be initially wider than screen"
    static var testBinding = Binding<String>(get: { test }, set: {
//        print("New value: \($0)")
        test = $0 } )

    static var previews: some View {
        VStack(alignment: .leading) {
            Text("Description:")
            MultilineTextField("Enter some text here", text: testBinding, onCommit: {
                print("Final text: \(test)")
            })
                .overlay(RoundedRectangle(cornerRadius: 4).stroke(Color.black))
            Text("Something static here...")
            Spacer()
        }
        .padding()
    }
}
#endif

6
Ayrıca SwiftUI kullanarak özel arka planları etkinleştirmek backgroundColoriçin UITextField'ı UIColor.clearayarlamayı ve otomatik ilk yanıtlayıcıyı kaldırmayı düşünmelisiniz, çünkü MultilineTextFieldstek bir görünümde çoklu kullanırken kırılır (her tuş vuruşu, tüm metin alanları yanıtlayıcıyı yeniden almaya çalışır).
iComputerfreak

2
@ kdion4891 Bu cevapta başka bir sorudan açıklandığı gibi , sadece textField.textContainerInset = UIEdgeInsets.zero+ yapabilirsin textField.textContainer.lineFragmentPadding = 0ve iyi çalışıyor 👌🏻 @Asperi Belirtildiği gibi yaparsanız, kaldırmanız gerekecek .padding(.leading, 4)ve .padding(.top, 8)aksi takdirde bozuk görünecektir. Ayrıca, değişebilir .foregroundColor(.gray)için .foregroundColor(Color(UIColor.tertiaryLabel))yer tutucular rengine uyacak TextField(koyu modu ile güncellenmesi ise eğer kontrol etmedi) s.
Rémi B.

3
Oh, ve ben de göründüğünde küçük bir "aksaklığı" düzeltmek @State private var dynamicHeight: CGFloat = 100için değiştirdim (kısa bir süre için büyük gösterir ve sonra küçülür). @State private var dynamicHeight: CGFloat = UIFont.systemFontSizeMultilineTextField
Rémi B.

2
@ q8yas, ile ilgili kodu yorumlayabilir veya kaldırabilirsinizuiView.becomeFirstResponder
Asperi

3
Yorumlarınız için herkese teşekkürler! Buna gerçekten memnun olurum. Sağlanan anlık görüntü, belirli bir amaç için yapılandırılmış bir yaklaşım demosudur. Tüm önerileriniz doğrudur, ancak amacınız için. Bu kodu kopyalayıp yapıştırmakta ve amacınız için dilediğiniz kadar yeniden yapılandırmakta özgürsünüz.
Asperi

31

A ile Text()bunu kullanarak başarabilirsiniz .lineLimit(nil)ve dokümantasyon bunun da çalışması gerektiğini önermektedir TextField(). Ancak, bunun şu anda beklendiği gibi çalışmadığını teyit edebilirim.

Bir hatadan şüpheleniyorum - Geri Bildirim Yardımcısı ile bir rapor doldurmanızı tavsiye ederim. Bunu yaptım ve kimlik FB6124711.

DÜZENLEME: iOS 14 için güncelleme: TextEditorbunun yerine yenisini kullanın.


FB6124711 kimliğini kullanarak hatayı arayabilmemin bir yolu var mı? Geri bildirim asistanını kontrol ettiğim için ama bu pek yardımcı
olmuyor

Bunu yapmanın bir yolu olduğuna inanmıyorum. Ancak raporunuzda bu kimlikten bahsedebilirsiniz, sizinkini açıklamak aynı sorunun bir kopyasıdır. Bu, triyaj ekibinin sorunun önceliğini artırmasına yardımcı olur.
Andrew Ebling

2
Bunun Xcode 11.0 beta 2 (11M337n) sürümünde hala bir sorun olduğunu doğruladı
Andrew Ebling

3
Bunun Xcode sürüm 11.0 beta 3'te (11M362v) hala bir sorun olduğu doğrulandı. Dizeyi "Bazı \ nmetin" olarak ayarlayabilirsiniz ve iki satırda görüntülenir, ancak yeni içerik yazmak yalnızca bir metin satırının, görünümünüzün çerçevesi dışında yatay olarak büyümesine neden olur.
Michael

3
Bu hala Xcode 11.4'te bir sorundur - Cidden ??? SwiftUI'yi bunun gibi hatalarla üretimde nasıl kullanacağız?
Trev14

29

Bu, UITextView'ü Xcode Sürüm 11.0 beta 6'da tamamlar (hala Xcode 11 GM tohum 2'de çalışmaktadır):

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

1
TextField, Xcode Sürüm 11.0 (11A420a), GM Tohum 2, Eylül, 2019
e987

2
Bu bir VStack'te iyi çalışır, ancak bir Liste kullanırken satırın yüksekliği TextView'daki tüm metni gösterecek şekilde genişlemez. Bir kaç şey denedim: Değişen isScrollEnablediçinde TextViewuygulanması; TextView çerçevesinde sabit bir genişlik ayarlama; ve hatta TextView ve Text'i bir ZStack'e koymak (satırın Metin görünümünün yüksekliğine uyacak şekilde genişlemesi umuduyla) ancak hiçbir şey işe yaramıyor. Bu cevabın bir Listede de işe yarayacak şekilde nasıl uyarlanacağı konusunda tavsiyesi olan var mı?
MathewS

@Meo Flute, yüksekliği içeriğe uydurmak için bir uzakta var.
Abdullah

İsScrollEnabled'ı false olarak değiştirdim ve işe yarıyor, teşekkürler.
Abdullah

28

iOS 14

Denir TextEditor

struct ContentView: View {
    @State var text: String = "Multiline \ntext \nis called \nTextEditor"

    var body: some View {
        TextEditor(text: $text)
    }
}

Dinamik büyüyen yükseklik:

Yazarken büyümesini istiyorsanız, aşağıdaki gibi bir etiket ekleyin:

ZStack {
    TextEditor(text: $text)
    Text(text).opacity(0).padding(.all, 8) // <- This will solve the issue if it is in the same ZStack
}

Demo

Demo


iOS 13

Yerel UITextView Kullanımı

bu yapı ile SwiftUI kodunda yerel UITextView'ı kullanabilirsiniz:

struct TextView: UIViewRepresentable {
    
    typealias UIViewType = UITextView
    var configuration = { (view: UIViewType) in }
    
    func makeUIView(context: UIViewRepresentableContext<Self>) -> UIViewType {
        UIViewType()
    }
    
    func updateUIView(_ uiView: UIViewType, context: UIViewRepresentableContext<Self>) {
        configuration(uiView)
    }
}

Kullanım

struct ContentView: View {
    var body: some View {
        TextView() {
            $0.textColor = .red
            // Any other setup you like
        }
    }
}

Avantajlar:

  • İOS 13 desteği
  • Eski kodla paylaşıldı
  • Yıllarca test edildi UIKit
  • Tamamen özelleştirilebilir
  • Orijinalin diğer tüm faydaları UITextView

3
Bu yanıta bakan ve gerçek metnin TextView yapısına nasıl iletileceğini merak eden biri varsa, textColor'u ayarlayan satırın altına aşağıdaki satırı ekleyin: $ 0.text = "Bazı metin"
Mattl

1
Metni bir değişkene nasıl bağlarsınız? Veya metni başka türlü geri almak?
biomiker

1
İlk seçenek zaten metin bağlamasına sahiptir. İkincisi bir standarttır UITextView. UIKit'te genellikle yaptığınız gibi onunla etkileşim kurabilirsiniz.
Mojtaba Hosseini

13

Şu anda en iyi çözüm oluşturduğum bu paketi kullanmak. TextView .

Swift Paket Yöneticisini kullanarak kurabilirsiniz (BENİOKU'da açıklanmıştır). Değiştirilebilir düzenleme durumuna ve çok sayıda özelleştirmeye izin verir (ayrıca README'de ayrıntılı olarak açıklanmıştır).

İşte bir örnek:

import SwiftUI
import TextView

struct ContentView: View {
    @State var input = ""
    @State var isEditing = false

    var body: some View {
        VStack {
            Button(action: {
                self.isEditing.toggle()
            }) {
                Text("\(isEditing ? "Stop" : "Start") editing")
            }
            TextView(text: $input, isEditing: $isEditing)
        }
    }
}

Bu örnekte, önce iki @Statedeğişken tanımlıyorsunuz . Bunlardan biri, TextView'in her yazıldığında yazdığı metin için, diğeri ise isEditingTextView'in durumu içindir.

TextView seçildiğinde isEditingdurumu değiştirir. Düğmeye tıkladığınızda, bu aynı zamanda isEditingklavyeyi gösterecek ve ne zaman TextView öğesini seçecek ve TextView ne zaman trueseçimini kaldıracak durumu değiştirir false.


1
Depoya bir sorun ekleyeceğim, ancak Asperi'nin orijinal çözümüne benzer bir sorunu var, bir VStack'te harika çalışıyor, ancak ScrollView'da değil.
RogerTheShrubber

No such module 'TextView'
Alex Bartiş

Düzenle: MacOS hedefliyorsanız fakat çerçeve sırf UIViewRepresentable ait UIKit destekler
Alex Bartis'in

11

@Meo Flute'un cevabı harika! Ancak çok aşamalı metin girişi için çalışmaz. @ Asperi'nin cevabıyla birleştirildiğinde, işte bunun için düzeltildi ve ayrıca eğlence için yer tutucu desteğini de ekledim!

struct TextView: UIViewRepresentable {
    var placeholder: String
    @Binding var text: String

    var minHeight: CGFloat
    @Binding var calculatedHeight: CGFloat

    init(placeholder: String, text: Binding<String>, minHeight: CGFloat, calculatedHeight: Binding<CGFloat>) {
        self.placeholder = placeholder
        self._text = text
        self.minHeight = minHeight
        self._calculatedHeight = calculatedHeight
    }

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

    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.delegate = context.coordinator

        // Decrease priority of content resistance, so content would not push external layout set in SwiftUI
        textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

        textView.isScrollEnabled = false
        textView.isEditable = true
        textView.isUserInteractionEnabled = true
        textView.backgroundColor = UIColor(white: 0.0, alpha: 0.05)

        // Set the placeholder
        textView.text = placeholder
        textView.textColor = UIColor.lightGray

        return textView
    }

    func updateUIView(_ textView: UITextView, context: Context) {
        textView.text = self.text

        recalculateHeight(view: textView)
    }

    func recalculateHeight(view: UIView) {
        let newSize = view.sizeThatFits(CGSize(width: view.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
        if minHeight < newSize.height && $calculatedHeight.wrappedValue != newSize.height {
            DispatchQueue.main.async {
                self.$calculatedHeight.wrappedValue = newSize.height // !! must be called asynchronously
            }
        } else if minHeight >= newSize.height && $calculatedHeight.wrappedValue != minHeight {
            DispatchQueue.main.async {
                self.$calculatedHeight.wrappedValue = self.minHeight // !! must be called asynchronously
            }
        }
    }

    class Coordinator : NSObject, UITextViewDelegate {

        var parent: TextView

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

        func textViewDidChange(_ textView: UITextView) {
            // This is needed for multistage text input (eg. Chinese, Japanese)
            if textView.markedTextRange == nil {
                parent.text = textView.text ?? String()
                parent.recalculateHeight(view: textView)
            }
        }

        func textViewDidBeginEditing(_ textView: UITextView) {
            if textView.textColor == UIColor.lightGray {
                textView.text = nil
                textView.textColor = UIColor.black
            }
        }

        func textViewDidEndEditing(_ textView: UITextView) {
            if textView.text.isEmpty {
                textView.text = parent.placeholder
                textView.textColor = UIColor.lightGray
            }
        }
    }
}

Bunu şu şekilde kullanın:

struct ContentView: View {
    @State var text: String = ""
    @State var textHeight: CGFloat = 150

    var body: some View {
        ScrollView {
            TextView(placeholder: "", text: self.$text, minHeight: self.textHeight, calculatedHeight: self.$textHeight)
            .frame(minHeight: self.textHeight, maxHeight: self.textHeight)
        }
    }
}

Bunu severim. Yer tutucu çalışmıyor gibi görünüyor, ancak baştan başlamak faydalı oldu. UIColor.lightGray ve UIColor.black yerine UIColor.label yerine UIColor.tertiaryLabel gibi semantik renkleri kullanmanızı öneririm, böylece hem açık hem de karanlık mod desteklenir.
Helam

@Helam Yer tutucunun nasıl çalışmadığını açıklamanın bir sakıncası var mı?
Daniel Tseng

@DanielTseng görünmüyor. Nasıl davranması gerekiyor? Metnin boş olup olmadığını göstermesini bekliyordum ama bana hiç görünmüyor.
Helam

@Helam, Örneğimde, boş olması gereken yer tutucum var. Başka bir şeyle değiştirmeyi denediniz mi? ("" Yerine "Merhaba Dünya!")
Daniel Tseng

Evet benimkinde onu başka bir şey olarak ayarladım.
Helam

3

SwiftUI TextView (UIViewRepresentable) şu parametrelerle kullanılabilir: fontStyle, isEditable, backgroundColor, borderColor & border Width

TextView (metin: self. $ ViewModel.text, fontStyle: .body, isEditable: true, backgroundColor: UIColor.white, borderColor: UIColor.lightGray, borderWidth: 1.0) .padding ()

TextView (UIViewRepresentable)

struct TextView: UIViewRepresentable {

@Binding var text: String
var fontStyle: UIFont.TextStyle
var isEditable: Bool
var backgroundColor: UIColor
var borderColor: UIColor
var borderWidth: CGFloat

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

func makeUIView(context: Context) -> UITextView {

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

    myTextView.font = UIFont.preferredFont(forTextStyle: fontStyle)
    myTextView.isScrollEnabled = true
    myTextView.isEditable = isEditable
    myTextView.isUserInteractionEnabled = true
    myTextView.backgroundColor = backgroundColor
    myTextView.layer.borderColor = borderColor.cgColor
    myTextView.layer.borderWidth = borderWidth
    myTextView.layer.cornerRadius = 8
    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) {
        self.parent.text = textView.text
    }
}

}


Çok satırlı metin alanına varsayılan bir metni nasıl eklerim?
Learn2Code

3

Xcode 12 ve iOS14 için mevcut , gerçekten çok kolay.

import SwiftUI

struct ContentView: View {
    
    @State private var text = "Hello world"
    
    var body: some View {
        TextEditor(text: $text)
    }
}

bu sadece iOS14 ile çalışıyorsanız değil, ya kullanıcı hala iOS13 kullanıyorsa
Di Nerd

3

MacOS uygulaması

struct MultilineTextField: NSViewRepresentable {
    
    typealias NSViewType = NSTextView
    private let textView = NSTextView()
    @Binding var text: String
    
    func makeNSView(context: Context) -> NSTextView {
        textView.delegate = context.coordinator
        return textView
    }
    func updateNSView(_ nsView: NSTextView, context: Context) {
        nsView.string = text
    }
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }
    class Coordinator: NSObject, NSTextViewDelegate {
        let parent: MultilineTextField
        init(_ textView: MultilineTextField) {
            parent = textView
        }
        func textDidChange(_ notification: Notification) {
            guard let textView = notification.object as? NSTextView else { return }
            self.parent.text = textView.string
        }
    }
}

ve nasıl kullanılır

struct ContentView: View {

    @State var someString = ""

    var body: some View {
         MultilineTextField(text: $someString)
    }
}

0

TextEditor(text: $text)Yükseklik gibi şeyler için herhangi bir değiştiriciyi kullanabilir ve sonra ekleyebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.