SwiftUI에서 높이 가변 TextEditor 사용

12333 단어 SwiftSwiftUI

소개



자신이 조사한 한이라면, SwiftUI 단체에서는 구현할 수 있을 것 같지 않기 때문에, UIKit를 병용하는 방법으로 구현했습니다.

완제품





구현



먼저 SwiftUI에서 UIKit을 호출하기 위해 UIViewRepresentable을 준수하는 View를 만듭니다.
설명은 코드의 주석을 참조하십시오.
struct DynamicHeightTextview: UIViewRepresentable {

    //入力値を反映するプロパティ
    @Binding var text: String

    //入力値を考慮したTextViewの高さを保持するプロパティ
    @Binding var height: CGFloat

    let textView = UITextView()

    //実装必須
    func makeUIView(context: Context) -> UITextView {
        textView.backgroundColor = .clear
        textView.font = .systemFont(ofSize: 16)
        textView.delegate = context.coordinator

        return textView
    }

    //実装必須
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
    }

    //Delegateメソッドを定義したクラスを返す
    func makeCoordinator() -> Coordinator {
        return Coordinator(dynamicHeightTextView: self)
    }

    //UITextViewのDelegateメソッドを実装する
    class Coordinator: NSObject, UITextViewDelegate {

        let dynamicHeightTextView: DynamicHeightTextview
        let textView: UITextView

        init(dynamicHeightTextView: DynamicHeightTextview) {
            self.dynamicHeightTextView = dynamicHeightTextView
            self.textView = dynamicHeightTextView.textView
        }

        func textViewDidChange(_ textView: UITextView) {
            dynamicHeightTextView.text = textView.text
            let textViewSize = textView.sizeThatFits(textView.bounds.size)
            dynamicHeightTextView.height = textViewSize.height
        }
    }
}


그런 다음 DynamicHeightTextview를 한 번 더 래핑한 View를 만들고 여기에서 높이 반영과 Placeholder를 추가합니다.
struct DynamicHeightTextEditor: View {

    @Binding var text: String
    @State var textHeight: CGFloat = 0

    var placeholder: String
    var minHeight: CGFloat
    var maxHeight: CGFloat

    //TextEditorの高さを保持するプロパティ
    var textEditorHeight: CGFloat {
        if textHeight < minHeight { 
            return minHeight
        }

        if textHeight > maxHeight {
            return maxHeight
        }

        return textHeight
    }

    var body: some View {
        ZStack {
            //TextEditorの背景色
            Color(red: 0.933, green: 0.917, blue: 0.956)

            //Placeholder
            if text.isEmpty {
                HStack {
                    Text(placeholder)
                        .foregroundColor(Color(red: 0.62, green: 0.62, blue: 0.62))
                        .padding(.leading, 2)
                    Spacer()
                }
            }

            DynamicHeightTextview(text: $text, height: $textHeight)
        }
        .clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
        .frame(height: textEditorHeight) //← ここで高さを反映
    }
}

사용방법


struct ContentView: View {
    @State var text = ""
    var body: some View {
        DynamicHeightTextEditor(text: $text, placeholder: "テキストを入力", minHeight: 35, maxHeight: 150)
            .padding(.leading, 10)
            .padding(.trailing, 10)
    }
}

이상입니다.

좋은 웹페이지 즐겨찾기