SwiftUI에서 여러 줄 TextField를 어떻게 생성합니까?


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
저는 lineLimit ()을 사용하여 GM 인 Xcode 버전 11.0 (11A419c)에서 swiftui로 여러 줄 텍스트 필드를 만들려고했습니다. 여전히 작동하지 않습니다. 나는 애플이 아직 이것을 고치지 않았다는 것을 믿을 수 없다. 여러 줄 텍스트 필드는 모바일 앱에서 매우 일반적입니다.
987 회

답변:


45

업데이트 : Xcode11 베타 4는 이제를 지원하지만 편집 가능한 여러 줄 텍스트를 작동하는 가장 좋은 방법은 TextViewa를 래핑하는 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

여기에 이미지 설명 입력


대단한 임시 해결! 순수한 SwiftUI를 사용하여 해결할 수있을 때까지 수락합니다.
gabriellanata 19

7
이 솔루션을 사용하면 이미 줄 바꿈이있는 텍스트를 표시 할 수 있지만 자연스럽게 긴 줄을 끊거나 줄 바꿈하지 않는 것 같습니다. (텍스트는 프레임 밖에서 한 줄에 수평으로 계속 커집니다.) 줄 바꿈 할 긴 줄을 얻는 방법에 대한 아이디어가 있습니까?
Michael

5
게시자가있는 EnvironmentObject 대신 State를 사용하고 MultilineTextView에 바인딩으로 전달하면 작동하지 않는 것 같습니다. 변경 사항을 주에 다시 반영하려면 어떻게해야합니까?
회색

environmentObject를 사용하지 않고 textview에서 기본 텍스트를 설정하는 방법이 있습니까?
Learn2Code

77

좋아, 나는 @sas 접근 방식으로 시작했지만 콘텐츠에 맞는 여러 줄 텍스트 필드 등의 모양과 느낌이 정말로 필요했습니다. 여기에 제가 가지고있는 것이 있습니다. 다른 사람에게 도움이되기를 바랍니다. Xcode 11.1을 사용했습니다.

제공된 사용자 정의 MultilineTextField에는 다음이 있습니다.
1. 콘텐츠 맞춤
2. 자동 초점
3. 자리 표시 자
4. 커밋시

콘텐츠에 맞는 swiftui 여러 줄 텍스트 필드 미리보기 자리 표시 자 추가

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
또한 SwiftUI를 사용하여 사용자 정의 배경을 활성화 backgroundColor하기 UIColor.clear위해 UITextField를 설정하고 auto-firstresponder를 제거하는 것에 대해 생각해야합니다 MultilineTextFields. 한 뷰에서 여러 개 를 사용할 때 중단되기 때문입니다 (모든 키 입력, 모든 텍스트 필드가 응답자를 다시 가져 오려고 시도합니다).
iComputerfreak

2
@ kdion4891으로는 설명 다른 질문에서이 대답 , 당신은 그냥 할 수있는 textField.textContainerInset = UIEdgeInsets.zero+ textField.textContainer.lineFragmentPadding = 0와 그것을 잘 👌🏻 @Asperi 작동 당신이 경우에 언급 한 바와 같이, 당신은 다음 제거해야 .padding(.leading, 4)하고 .padding(.top, 8)그렇지 않으면 깨진 살펴 보겠습니다. 또한, 당신은 변경 될 수 있습니다 .foregroundColor(.gray)에 대한 .foregroundColor(Color(UIColor.tertiaryLabel))의 자리 '색상을 일치하는 TextField(어두운 모드를 업데이트하는 경우 만약 내가 확인하지 않았다)의.
Rémi B.

3
아, 그리고 나는 또한 나타날 때 작은 "글리치"를 수정하기 위해 변경 @State private var dynamicHeight: CGFloat = 100했습니다 (짧은 시간 동안 크게 보이다가 축소됨). @State private var dynamicHeight: CGFloat = UIFont.systemFontSizeMultilineTextField
Rémi B.

2
@ q8yas, 당신은 관련 코드를 주석하거나 제거 할 수 있습니다uiView.becomeFirstResponder
Asperi

3
의견을 보내 주셔서 감사합니다! 정말 감사합니다. 제공된 스냅 샷은 특정 목적을 위해 구성된 접근 방식의 데모입니다. 귀하의 모든 제안은 정확하지만 귀하의 목적을위한 것입니다. 이 코드를 복사하여 붙여넣고 원하는만큼 재구성 할 수 있습니다.
Asperi

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, 2019 년 9 월
e987의

2
이것은 VStack에서 잘 작동하지만 List를 사용할 때 행의 높이가 확장되어 TextView의 모든 텍스트를 표시하지 않습니다. 나는 몇 가지를 시도했다 : 변화 isScrollEnabledTextView구현; TextView 프레임에 고정 너비 설정; 그리고 TextView와 Text를 ZStack에 넣는 것 (행이 Text 뷰의 높이와 일치하도록 확장되기를 바라기 위해)하지만 아무것도 작동하지 않습니다. 누구 든지이 답변을 목록에서 작동하도록 조정하는 방법에 대한 조언이 있습니까?
MathewS

@Meo Flute는 높이를 콘텐츠와 일치시키기 위해 멀리 있습니다.
Abdullah

isScrollEnabled를 false로 변경했으며 작동합니다.
Abdullah

26

를 사용하면 Text()을 사용 .lineLimit(nil)하여이 작업을 수행 할 수 있으며 문서에서는 이것이 작동 해야한다고 제안합니다 TextField(). 그러나 현재 예상대로 작동하지 않음을 확인할 수 있습니다.

버그가 의심됩니다. 피드백 도우미로 신고 할 것을 권장합니다. 나는 이것을했고 ID는 FB6124711입니다.

편집 : iOS 14 용 업데이트 : TextEditor대신 새로운 것을 사용하십시오 .


ID FB6124711을 사용하여 버그를 검색 할 수있는 방법이 있습니까? 나는 피드백 조수에 확인하고 있지만, 매우 도움이되지이다로
CrazyPro007

그렇게 할 방법이 없다고 생각합니다. 하지만 보고서에서 해당 ID를 언급 할 수 있으며, 본인의 ID는 동일한 문제의 속임수라고 설명 할 수 있습니다. 이렇게하면 심사 팀이 문제의 우선 순위를 높일 수 있습니다.
Andrew Ebling 19.06.06

2
이 여전히 엑스 코드 버전 11.0 베타 2 (11M337n)에 문제가 확정
앤드류 Ebling

3
Xcode 버전 11.0 베타 3 (11M362v)에서 여전히 문제임을 확인했습니다. 문자열을 "Some \ ntext"로 설정하면 두 줄에 표시되지만 새 내용을 입력하면보기 프레임 밖에서 한 줄의 텍스트가 가로로 커집니다.
Michael

3
이것은 Xcode 11.4에서 여전히 문제입니다-심각하게 ??? 이와 같은 버그가있는 프로덕션에서 SwiftUI를 어떻게 사용해야합니까?
Trev14

16

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
누군가이 답변을보고 실제 텍스트를 TextView 구조체에 전달하는 방법을 궁금해하는 경우 textColor를 설정하는 줄 아래에 다음 줄을 추가합니다. $ 0.text = "Some text"
Mattl

1
텍스트를 변수에 어떻게 바인딩합니까? 아니면 텍스트를 검색 하시겠습니까?
biomiker

1
첫 번째 옵션에는 이미 텍스트 바인딩이 있습니다. 두 번째는 표준 UITextView입니다. UIKit에서 일반적으로하는 것처럼 상호 작용할 수 있습니다.
Mojtaba Hosseini

12

현재 가장 좋은 해결책은 내가 만든 TextView 라는 패키지를 사용하는 것입니다 .

Swift Package Manager를 사용하여 설치할 수 있습니다 (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가 입력 될 때마다 TextView가 쓰는 텍스트 용이고 다른 하나는 isEditingTextView 의 상태 용입니다.

TextView를 선택하면 isEditing상태를 전환합니다 . 버튼을 클릭하면 isEditing키보드를 표시하는 상태를 전환하고 . 일 true때 TextView를 선택하고 false.


1
저장소에 문제를 추가 할 것이지만 Asperi의 원래 솔루션과 비슷한 문제가 있습니다. VStack에서는 잘 작동하지만 ScrollView에서는 작동하지 않습니다.
RogerTheShrubber

No such module 'TextView'
Alex Bartiş

편집 : macOS를 대상으로하지만 프레임 워크는 UIViewRepresentable 때문에 UIKit 만 지원합니다
Alex Bartiş

10

@Meo Flute의 대답은 훌륭합니다! 그러나 다단계 텍스트 입력에는 작동하지 않습니다. 그리고 @Asperi의 답변과 결합하여 여기에 대한 수정 사항이 있으며 재미를 위해 자리 표시 자에 대한 지원도 추가했습니다!

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.lightGray 대신 UIColor.lightGray 및 UIColor.label 대신 UIColor.tertiaryLabel과 같은 의미 색상을 사용하는 것이 좋습니다.
Helam

@Helam 자리 표시자가 어떻게 작동하지 않는지 설명해 주시겠습니까?
Daniel Tseng

@DanielTseng 그것은 나타나지 않습니다. 어떻게 작동해야합니까? 텍스트가 비어 있는지 표시 할 것으로 예상했지만 절대 표시되지 않습니다.
Helam

@Helam, 내 예에서 자리 표시자가 비어 있습니다. 다른 것으로 변경해 보셨습니까? ( ""대신 "Hello World!")
Daniel Tseng

예, 나는 그것을 다른 것으로 설정했습니다.
Helam

2

다음 매개 변수를 사용할 수있는 SwiftUI TextView (UIViewRepresentable) : fontStyle, isEditable, backgroundColor, borderColor 및 border Width

TextView (text : 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
    }
}

}


1

사용 가능한을 위해 엑스 코드 (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)
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.