// // ComposeTextView.swift // Tusker // // Created by Shadowfacts on 8/18/20. // Copyright © 2020 Shadowfacts. All rights reserved. // import SwiftUI struct ComposeTextView: View { @Binding private var text: String private let placeholder: Text? private let minHeight: CGFloat private var heightDidChange: ((CGFloat) -> Void)? private var backgroundColor = UIColor.secondarySystemBackground private var fontSize: CGFloat = 20 @State private var height: CGFloat? init(text: Binding, placeholder: Text?, minHeight: CGFloat = 150) { self._text = text self.placeholder = placeholder self.minHeight = minHeight } var body: some View { ZStack(alignment: .topLeading) { Color(backgroundColor) if text.isEmpty, let placeholder = placeholder { placeholder .font(.system(size: fontSize)) .foregroundColor(.secondary) .offset(x: 4, y: 8) } WrappedTextView( text: $text, textDidChange: self.textDidChange, font: .systemFont(ofSize: fontSize) ) .frame(height: height ?? minHeight) } } private func textDidChange(textView: UITextView) { height = max(minHeight, textView.contentSize.height) heightDidChange?(height!) } func heightDidChange(_ callback: @escaping (CGFloat) -> Void) -> Self { var copy = self copy.heightDidChange = callback return copy } func backgroundColor(_ color: UIColor) -> Self { var copy = self copy.backgroundColor = color return copy } func fontSize(_ size: CGFloat) -> Self { var copy = self copy.fontSize = size return copy } } struct WrappedTextView: UIViewRepresentable { typealias UIViewType = UITextView @Binding var text: String var textDidChange: ((UITextView) -> Void)? var font = UIFont.systemFont(ofSize: 20) func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.delegate = context.coordinator textView.isEditable = true textView.backgroundColor = .clear textView.font = font textView.textContainer.lineBreakMode = .byWordWrapping return textView } func updateUIView(_ uiView: UITextView, context: Context) { uiView.text = text context.coordinator.text = $text context.coordinator.didChange = textDidChange // wait until the next runloop iteration so that SwiftUI view updates have finished and // the text view knows its new content size DispatchQueue.main.async { self.textDidChange?(uiView) } } func makeCoordinator() -> Coordinator { return Coordinator(text: $text, didChange: textDidChange) } class Coordinator: NSObject, UITextViewDelegate { var text: Binding var didChange: ((UITextView) -> Void)? init(text: Binding, didChange: ((UITextView) -> Void)?) { self.text = text self.didChange = didChange } func textViewDidChange(_ textView: UITextView) { text.wrappedValue = textView.text didChange?(textView) } } } //struct ComposeTextView_Previews: PreviewProvider { // static var previews: some View { // ComposeTextView() // } //}