// // StatusEditorView.swift // // // Created by MainasuK Cirno on 2021-7-16. // import UIKit import SwiftUI import UITextView_Placeholder public struct StatusEditorView: UIViewRepresentable { @Binding var string: String let placeholder: String let width: CGFloat let attributedString: NSAttributedString let keyboardType: UIKeyboardType @Binding var viewDidAppear: Bool public init( string: Binding, placeholder: String, width: CGFloat, attributedString: NSAttributedString, keyboardType: UIKeyboardType, viewDidAppear: Binding ) { self._string = string self.placeholder = placeholder self.width = width self.attributedString = attributedString self.keyboardType = keyboardType self._viewDidAppear = viewDidAppear } public func makeUIView(context: Context) -> UITextView { let textView = UITextView(frame: .zero) textView.placeholder = placeholder textView.isScrollEnabled = false textView.font = .preferredFont(forTextStyle: .body) textView.textColor = .label textView.keyboardType = keyboardType textView.delegate = context.coordinator textView.backgroundColor = .clear textView.translatesAutoresizingMaskIntoConstraints = false let widthLayoutConstraint = textView.widthAnchor.constraint(equalToConstant: 100) widthLayoutConstraint.priority = .required - 1 context.coordinator.widthLayoutConstraint = widthLayoutConstraint return textView } public func updateUIView(_ textView: UITextView, context: Context) { // preserve currently selected text range to prevent cursor jump let currentlySelectedRange = textView.selectedRange // update content // textView.attributedText = attributedString textView.text = string // update layout context.coordinator.updateLayout(width: width) // set becomeFirstResponder if viewDidAppear { viewDidAppear = false textView.becomeFirstResponder() } // restore selected text range textView.selectedRange = currentlySelectedRange } public func makeCoordinator() -> Coordinator { Coordinator(self) } public class Coordinator: NSObject, UITextViewDelegate { var parent: StatusEditorView var widthLayoutConstraint: NSLayoutConstraint? init(_ parent: StatusEditorView) { self.parent = parent } public func textViewDidChange(_ textView: UITextView) { // prevent break IME input if textView.markedTextRange == nil { parent.string = textView.text } } func updateLayout(width: CGFloat) { guard let widthLayoutConstraint = widthLayoutConstraint else { return } widthLayoutConstraint.constant = width widthLayoutConstraint.isActive = true } } }