TextView component in swiftUI || adjustable height textField || Dynamic height textField in SwiftUI || TextField height change at runtime

Solution:

//# MARK: - TextView Component


fileprivate struct UITextViewAdjustableUIViewRepresentable {

    typealias UIViewType = UITextView


    @Binding var textString

    @Binding var calHeightCGFloat

    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 updateUI(_ uiView: UITextView, context: UIViewRepresentableContext< UITextViewAdjustable >) {

        if uiView.text != self.text {

            uiView.text = self.text

        }

        if uiView.window != nil!uiView.isFirstResponder {

            uiView.becomeFirstResponder()

        }

        UITextViewAdjustable.adjustcalculateHeight(view: uiView, result: $calHeight)

    }


    fileprivate static func adjustcalculateHeight(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: $calHeight, onDone: onDone)

    }


    final class CoordinatorNSObjectUITextViewDelegate {

        var textBinding<String>

        var calHeightBinding<CGFloat>

        var onDone: (() -> Void)?


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

            self.text = text

            self. calHeight = 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 {

            UITextViewAdjustable.adjustcalculateHeight(view: textView, result: calculatedHeight)

            return true

        }

    }


}


struct adjustTextFieldView {


    private var placeholderString

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


    @Binding private var textString

    private var internalTextBinding<String> {

        Binding<String>(get: { self.text } ) {

            self.text = $0

            self.showingPlaceholder = $0.isEmpty

        }

    }


    @State private var dynamicHeightCGFloat = 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 bodysome View {

        UITextViewAdjustable(text: self.internalTextcalHeight$dynamicHeight, onDone: onCommit)

            .frame(minHeight: dynamicHeight, maxHeight: dynamicHeight)

            .background(placeholderView, alignment: .topLeading)

    }


    var placeholderViewsome View {

        Group {

            if showingPlaceholder {

                Text(placeholder).foregroundColor(.gray)

                    .padding(.leading4)

                    .padding(.top8)

            }

        }

    }

}



Use the above code inside your contentView...Call the dynamic height

textView using the below code.





             var test:String = ""

             let testBinding = Binding<String>(get: { test }, set: {

                    test = $0 } )


            return AnyView(adjustTextField("Enter some text here", text: testBinding, onCommit: {

                print("Final text: \(test)")

            }))


Comments

Popular posts from this blog

Invalid bundle error while upload the app to the app Store

store cgpoint in userdefaults iOS swift