Issue #843
This can be used in message bar input or some popover form. We use sizeThatFits
to calculate the height so that it grow under certain height limit
import SwiftUI
import UIKit
struct MessageTextField: View {
let placeholder: String
@Binding var text: String
@Binding var isEditing: Bool
@State private var height: CGFloat = 100
var body: some View {
UITextViewWrapper(
text: $text,
isEditing: $isEditing,
height: $height
)
.frame(height: height)
.background(placeholderView, alignment: .topLeading)
}
var placeholderView: some View {
Group {
if text.isEmpty {
Text(placeholder)
.foregroundColor(Asset.textSecondary.color)
.font(.system(size: 16))
.padding(.leading)
}
}
}
}
private struct UITextViewWrapper: UIViewRepresentable {
typealias UIViewType = UITextView
@Binding var text: String
@Binding var isEditing: Bool
@Binding var height: CGFloat
private static let maxHeight: CGFloat = 100
func makeUIView(context: Context) -> UITextView {
let textField = UITextView()
textField.delegate = context.coordinator
textField.isEditable = true
textField.font = UIFont.systemFont(ofSize: 16)
textField.isSelectable = true
textField.isUserInteractionEnabled = true
textField.isScrollEnabled = true
textField.backgroundColor = UIColor.clear
textField.textColor = .textPrimary
textField.tintColor = .textPrimary
textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
return textField
}
func updateUIView(_ uiView: UITextView, context: Context) {
if uiView.text != text {
uiView.text = text
}
calculateHeight(view: uiView)
}
private func calculateHeight(
view: UIView
) {
let size = view.sizeThatFits(
CGSize(
width: view.frame.size.width,
height: CGFloat.greatestFiniteMagnitude
)
)
guard height != size.height else { return }
DispatchQueue.main.async {
height = min(size.height, Self.maxHeight)
}
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
final class Coordinator: NSObject, UITextViewDelegate {
let parent: UITextViewWrapper
init(parent: UITextViewWrapper) {
self.parent = parent
}
func textViewDidChange(_ uiView: UITextView) {
parent.text = uiView.text
}
func textViewDidBeginEditing(_: UITextView) {
parent.isEditing = true
}
func textViewDidEndEditing(_: UITextView) {
parent.isEditing = false
}
}
}