मैं स्विफ्टयूआई में मल्टीलाइन टेक्स्टफिल्ड कैसे बनाऊं?


85

मैं SwiftUI में एक बहु-पाठ TextField बनाने की कोशिश कर रहा हूं, लेकिन मैं यह पता नहीं लगा सकता कि कैसे।

वर्तमान में मेरे पास यह कोड है:

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

लेकिन यह आउटपुट है:

यहां छवि विवरण दर्ज करें


1
मैं सिर्फ Xcode संस्करण 11.0 (11A419c), जीएम, लाइनलिमिट () का उपयोग करके स्विफ्टुई के साथ एक बहुस्तरीय टेक्स्टफील्ड बनाने की कोशिश की। यह अब भी काम नहीं करता है। मुझे विश्वास नहीं हो रहा है कि Apple ने अभी तक इसे ठीक नहीं किया है। मोबाइल ऐप्स में एक मल्टीलाइन टेक्स्टफील्ड काफी सामान्य है।
e987

जवाबों:


45

अद्यतन: जबकि Xcode11 बीटा 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

यहां छवि विवरण दर्ज करें


महान अस्थायी हल! अब तक के लिए स्वीकार करना इसे शुद्ध स्विफ्टयूआई का उपयोग करके हल किया जा सकता है।
गाब्रीलानाटा

7
यह समाधान आपको उस पाठ को प्रदर्शित करने की अनुमति देता है जिसमें पहले से ही इसकी नई लाइनें हैं, लेकिन यह स्वाभाविक रूप से लंबी लाइनों को तोड़ने / लपेटने के लिए प्रतीत नहीं होता है। (पाठ केवल फ्रेम के बाहर एक पंक्ति में क्षैतिज रूप से बढ़ता रहता है।) किसी भी विचार को लपेटने के लिए लंबी लाइनें कैसे प्राप्त करें?
माइकल

5
अगर मैं स्टेट (एक प्रकाशक के साथ एक EnvironmentObject के बजाय) का उपयोग करता हूं और इसे MultilineTextView के लिए बाध्यकारी के रूप में पास करता हूं, तो यह काम नहीं करता है। मैं राज्य में परिवर्तन कैसे प्रतिबिंबित कर सकता हूं?
ग्रे

क्या पर्यावरण के उपयोग के बिना टेक्स्टव्यू में डिफ़ॉल्ट पाठ सेट करने का कोई तरीका है?
2:27 पर Learn2Code

77

ठीक है, मैंने @sas दृष्टिकोण के साथ शुरुआत की, लेकिन यह वास्तव में सामग्री फिट, आदि के साथ मल्टी-लाइन पाठ क्षेत्र के रूप में देखने और महसूस करने की आवश्यकता है। आशा है कि यह किसी और के लिए उपयोगी होगा ... प्रयुक्त Xcode 11.1।

बशर्ते कस्टम MultilineTextField में है:
1. सामग्री फिट
2. ऑटोफोकस
3. प्लेसहोल्डर
4. प्रतिबद्ध

सामग्री फिट के साथ स्विफ्टुई मल्टीलाइन टेक्स्टफील्ड का पूर्वावलोकन प्लेसहोल्डर जोड़ा गया

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
इसके अलावा, आपको स्विफ्टयूआई का उपयोग करके कस्टम पृष्ठभूमि को सक्षम करने के लिए और ऑटो-फर्स्टपोन्डर को हटाने के बारे में यूआईटैक्सफ़िल्ड backgroundColorकी स्थापना के बारे में सोचना चाहिए UIColor.clear, क्योंकि यह MultilineTextFieldsएक दृश्य में कई का उपयोग करते समय टूट जाता है (प्रत्येक कीस्ट्रोक, सभी पाठ क्षेत्र फिर से उत्तर प्राप्त करने का प्रयास करते हैं)।
iPputerfreak

2
@ kdion4891 जैसा कि एक अन्य प्रश्न से इस उत्तर में समझाया गया है , आप बस कर सकते हैं textField.textContainerInset = UIEdgeInsets.zero+ textField.textContainer.lineFragmentPadding = 0और यह ठीक काम करता है If @Asperi यदि आप उल्लेख के रूप में करते हैं, तो आपको फिर हटाने की आवश्यकता होगी .padding(.leading, 4)और .padding(.top, 8)अन्यथा यह टूटी हुई दिखेगी । इसके अलावा, आप प्लेसहोल्डर्स के रंग से मेल खाने के .foregroundColor(.gray)लिए बदल सकते हैं (अगर मैं डार्क मोड के साथ अपडेट कर रहा हूं तो मैं इसकी जांच नहीं कर सकता)। .foregroundColor(Color(UIColor.tertiaryLabel))TextField
रेमी बी।

3
ओह, और, मैं प्रकट होने पर एक छोटी "गड़बड़" को ठीक करने के @State private var dynamicHeight: CGFloat = 100लिए भी बदल गया (यह थोड़े समय के लिए बड़ा दिखाता है और फिर सिकुड़ जाता है)। @State private var dynamicHeight: CGFloat = UIFont.systemFontSizeMultilineTextField
रेमी बी।

2
@ q8yas, आप टिप्पणी कर सकते हैं या कोड से संबंधित हटा सकते हैंuiView.becomeFirstResponder
Asperi

3
टिप्पणियों के लिए सभी को धन्यवाद! मैं वास्तव में उसकी सराहना करता हूँ। प्रदान की गई स्नैपशॉट दृष्टिकोण का एक डेमो है, जिसे एक विशिष्ट उद्देश्य के लिए कॉन्फ़िगर किया गया था। आपके सभी प्रस्ताव सही हैं, लेकिन आपके उद्देश्यों के लिए। आप इस कोड को कॉपी-पेस्ट करने के लिए स्वतंत्र हैं और इसे फिर से कॉन्फ़िगर करें जितना आप अपने उद्देश्य के लिए चाहते हैं।
अस्पररी

28

यह Xcode संस्करण 11.0 बीटा 6 में UITextView को लपेटता है (अभी भी Xcode 11 GM बीज 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()
    }
}

1
TextField अभी भी Xcode वर्जन 11.0 (11A420a), GM Seed 2, Sept., 2019
e987

2
यह एक VStack में अच्छी तरह से काम करता है, लेकिन जब एक सूची का उपयोग करते हुए पंक्ति की ऊंचाई का विस्तार टेक्स्टव्यू के सभी पाठ दिखाने के लिए नहीं होता है। मैंने कुछ चीजों की कोशिश की है: कार्यान्वयन isScrollEnabledमें परिवर्तन TextView; TextView फ्रेम पर एक निश्चित चौड़ाई सेट करना; और यहां तक ​​कि टेक्स्ट व्यू और टेक्स्ट को एक ZStack में डालकर (इस उम्मीद में कि पंक्ति टेक्स्ट दृश्य की ऊंचाई से मेल खाने के लिए विस्तारित होगी) लेकिन कुछ भी काम नहीं करता है। क्या किसी को इस सूची में काम करने के लिए इस उत्तर को अनुकूलित करने के बारे में सलाह है?
मैथ्यू

@Meo Flute कंटेंट से मेल खाता ऊंचाई बनाने के लिए दूर है।
अब्दुल्ला

मैंने बदल दिया है .ScrollEnabled झूठे और यह काम करता है, धन्यवाद।
अब्दुल्ला

27

एक Text()का उपयोग कर आप इसे प्राप्त कर सकते हैं .lineLimit(nil), और प्रलेखन का सुझाव है कि इसके लिए भी काम करना चाहिएTextField() । हालाँकि, मैं पुष्टि कर सकता हूँ कि यह वर्तमान में अपेक्षित रूप से काम नहीं करता है।

मुझे एक बग पर संदेह है - प्रतिक्रिया सहायक के साथ रिपोर्ट दर्ज करने की सिफारिश करेंगे। मैंने ऐसा किया है और आईडी FB6124711 है।

EDIT: iOS 14 के लिए अपडेट: TextEditorइसके बजाय नए का उपयोग करें ।


वहाँ एक तरीका है कि मैं आईडी FB6124711 का उपयोग कर बग खोज सकते हैं? जैसा कि मैं प्रतिक्रिया सहायक पर जाँच कर रहा हूँ, लेकिन यह बहुत उपयोगी नहीं है
CrazyPro007

मेरा मानना ​​है कि ऐसा करने का कोई तरीका नहीं है। लेकिन आप अपनी रिपोर्ट में उस आईडी का उल्लेख कर सकते हैं, जो आपको समझाती है कि यह उसी मुद्दे का एक कारण है। इससे ट्राइएज टीम को मुद्दे की प्राथमिकता को बढ़ाने में मदद मिलती है।
एंड्रयू एबलिंग

2
इसकी पुष्टि अभी भी Xcode संस्करण 11.0 बीटा 2 (11M337n) में एक मुद्दा है
एंड्रयू

3
इस बात की पुष्टि अभी भी Xcode संस्करण 11.0 बीटा 3 (11M362v) में एक मुद्दा है। आप स्ट्रिंग को "Some \ ntext" पर सेट कर सकते हैं और यह दो लाइनों पर प्रदर्शित होगा, लेकिन नई सामग्री टाइप करने से आपके दृश्य के फ्रेम के बाहर, क्षैतिज रूप से बढ़ने के लिए पाठ की एक पंक्ति हो जाएगी।
माइकल

3
यह अभी भी Xcode 11.4 में एक मुद्दा है - गंभीरता से ??? हम इस तरह से बग के साथ उत्पादन में SwiftUI का उपयोग कैसे करें।
ट्रेव 14

17

iOS 14

यह कहा जाता है TextEditor

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

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

गतिशील बढ़ती ऊंचाई:

यदि आप चाहते हैं कि यह आपके अनुसार विकसित हो, तो इसे नीचे दिए गए लेबल के साथ एम्बेड करें:

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

डेमो

डेमो


iOS 13

मूल UITextView का उपयोग करना

आप इस संरचना के साथ SwiftUI कोड में मूल UITextView का उपयोग कर सकते हैं:

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

प्रयोग

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

लाभ:

  • IOS 13 के लिए समर्थन
  • विरासत कोड के साथ साझा किया गया
  • में वर्षों तक परीक्षण किया UIKit
  • पूरी तरह से अनुकूलन
  • मूल के अन्य सभी लाभ UITextView

3
अगर कोई भी इस उत्तर को देख रहा है और सोच रहा है कि टेक्स्टव्यू संरचना में वास्तविक पाठ को कैसे पास किया जाए, तो नीचे दी गई पंक्ति को उस पाठ के रूप में जोड़ें, जो पाठ सेट करता है: $ 0.text = "कुछ पाठ"
Mattl

1
आप पाठ को एक चर में कैसे बाँधते हैं? या अन्यथा पाठ पुनः प्राप्त करें?
बायोमाइकर

1
पहले विकल्प में पहले से ही टेक्स्ट बाइंडिंग है। दूसरा एक मानक है UITextView। आप इसके साथ बातचीत कर सकते हैं जैसा कि आप आमतौर पर UIKit में करते हैं।
Mojtaba होसैनी

12

वर्तमान में, सबसे अच्छा समाधान इस पैकेज का उपयोग करना है जिसे मैंने TextView कहा जाता है ।

आप इसे स्विफ्ट पैकेज मैनेजर (README में समझाया गया) का उपयोग करके स्थापित कर सकते हैं। यह टॉगल-सक्षम संपादन स्थिति और कई अनुकूलन (README में भी विस्तृत) के लिए अनुमति देता है।

यहाँ एक उदाहरण है:

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

उस उदाहरण में, आप पहले दो @Stateचर को परिभाषित करते हैं। एक पाठ के लिए है, जिसे TextView लिखते हैं जब भी इसे टाइप किया जाता है और दूसरा isEditingTextView की स्थिति के लिए होता है।

पाठ दृश्य, जब चयनित होता है, तो isEditingराज्य को टॉगल करता है। जब आप बटन पर क्लिक करते हैं, तो वह isEditingराज्य भी टॉगल करता है, जो कीबोर्ड को दिखाएगा और टेक्स्ट व्यू को कब चुनें true, और टेक्स्ट व्यू को अचयनित करें false


1
मैं रेपो पर एक मुद्दा जोड़ूंगा, लेकिन इसमें एस्परि के मूल समाधान के समान समस्या है, यह एक वीस्टैक में बहुत अच्छा काम करता है, लेकिन स्क्रॉलव्यू में नहीं।
रोजरशेरबर

No such module 'TextView'
एलेक्स बार्टिस

संपादित करें: आप macOS को लक्षित कर रहे हैं, लेकिन रूपरेखा केवल UIView की वजह से समर्थन करता है। संक्षिप्त
एलेक्स बार्टिएस

10

@Meo बांसुरी का जवाब बहुत अच्छा है! लेकिन यह मल्टीस्टेज टेक्स्ट इनपुट के लिए काम नहीं करता है। और @ अस्पररी के जवाब के साथ, यहाँ इसके लिए तय किया गया है और मैंने प्लेसहोल्डर के लिए समर्थन को सिर्फ मनोरंजन के लिए जोड़ा है!

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

इसे इस तरह उपयोग करें:

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

यह मुझे पंसद है। प्लेसहोल्डर काम नहीं करता है, लेकिन यह शुरू करने के लिए उपयोगी था। मेरा सुझाव है कि UIColor.tertiaryLabel की जगह UIColor.lightGray और UIColor.label जैसे UIColor.black के बजाय सिमेंटिक रंगों का उपयोग करें ताकि लाइट और डार्क मोड दोनों का समर्थन हो।
हेलम

@ हेलम आप समझाते हैं कि प्लेसहोल्डर कैसे काम नहीं कर रहा है?
डैनियल त्सेंग

@DanielTseng यह प्रदर्शित नहीं करता है। यह कैसे व्यवहार किया जाता है? मैं यह दिखाने की उम्मीद कर रहा था कि पाठ खाली है लेकिन यह कभी भी मेरे लिए नहीं दिखा।
हेलाम मार्क

@ हेलम, मेरे उदाहरण में, मेरे पास खाली रहने के लिए प्लेसहोल्डर है। क्या आपने इसे किसी और चीज़ में बदलने की कोशिश की है? ("हैलो वर्ल्ड!" "के बजाय")
डैनियल त्सेंग

हाँ, मैंने इसे कुछ और होने के लिए निर्धारित किया है।
हेलम

2

निम्नलिखित मापदंडों के साथ SwiftUI TextView (UIViewRepresentable) उपलब्ध हैं: fontStyle, isEditable, backgroundColor, BorderColor और सीमा चौड़ाई

TextView (पाठ: स्व। $ ViewModel.text, fontStyle: .body, isEditable: true, backgroundColor: UIColor.white, borderColor: UIColor.lightGray, borderWithth: 1.0) .pad ()

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

}


1

Xcode 12 और iOS14 के लिए उपलब्ध है , यह वास्तव में आसान है।

import SwiftUI

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

यह केवल अगर आप iOS14 के साथ काम कर रहे हैं, तो क्या होगा यदि उपयोगकर्ता अभी भी iOS13
Di Nerd

1

MacOS कार्यान्वयन

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

और कैसे उपयोग करें

struct ContentView: View {

@State var someString = ""

    var body: some View {
         MultilineTextField(text: $someString)
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.