TextView component in swiftUI || adjustable height textField || Dynamic height textField in SwiftUI || TextField height change at runtime
//# MARK: - TextView Component
fileprivate struct UITextViewAdjustable: UIViewRepresentable {
typealias UIViewType = UITextView
@Binding var text: String
@Binding var calHeight: CGFloat
var onDone: (() -> Void)?
func makeUIView(context: UIViewRepresentableContext<UIT
let textField = UITextView()
textField.delegate = context.coordinator
textField.isEditable = true
textField.font = UIFont.preferredFont(
textField.isSelectable = true
textField.isUserInteractionEna
textField.isScrollEnabled = false
textField.backgroundColor = UIColor.clear
if nil != onDone {
textField.returnKeyType = .done
}
textField.setContentCompressio
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(
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 Coordinator: NSObject, UITextViewDelegate {
var text: Binding<String>
var calHeight: Binding<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.recalculateH
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
UITextViewAdjustable.adjustcalculateHeight(view: textView, result: calculatedHeight)
return true
}
}
}
struct adjustTextField: 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 {
UITextViewAdjustable(text: self.internalText, calHeight: $dynamicHeight, onDone: onCommit)
.frame(minHeight: dynamicHeight, maxHeight: dynamicHeight)
.background(placeholderView, alignment: .topLeading)
}
var placeholderView: some View {
Group {
if showingPlaceholder {
Text(placeholder).foregroundCo
.padding(.leading, 4)
.padding(.top, 8)
}
}
}
}
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("
print("Final text: \(test)")
}))
Comments
Post a Comment