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

Saved Image in document directory and save path in coredata not able to fetch the image file iOS swift