I created this SwiftUI GrowingTextViewRepresentable, which represents a UITextView. I wish to preserve the selectedTextRange even after the main focus shifts to a different TextField/TextView. To realize this, I attempted preserving it with a Binding. I reserve it in textViewDidEndEditing, anticipating it to stay chosen when the main focus adjustments to a different textual content area. I then set it once more in updateUIView when the view masses. Nevertheless, it isn’t working as anticipated. What am I doing mistaken, or how can I obtain this?
FYI:
GrowingTextView is only a UITextView subclass, which will increase the peak when multiline textual content adjustments.
GrowingTextViewRepresentable Code:
import UIKit
import SwiftUI
import GrowingTextView
struct GrowingTextViewRepresentable: UIViewRepresentable {
let textView = GrowingTextView()
var placeHolder: String = ""
var customFont: UIFont = .systemFont(ofSize: 12)
var placeHolderColor: UIColor = .gray
var textColor: UIColor = .black
@Binding var textual content: String
@Binding var peak: CGFloat
@Binding var selectedText: String
@Binding var selectedTextRange: UITextRange?
func makeUIView(context: Context) -> GrowingTextView {
textView.delegate = context.coordinator
textView.font = customFont
textView.placeholder = placeHolder
textView.placeholderColor = placeHolderColor
textView.textColor = textColor
textView.backgroundColor = .clear
textView.clipsToBounds = true
return textView
}
func updateUIView(_ uiView: GrowingTextView, context: Context) {
uiView.textual content = textual content
if selectedTextRange != nil && uiView.selectedTextRange != selectedTextRange {
uiView.selectedTextRange = selectedTextRange
}
}
func makeCoordinator() -> Coordinator {
Coordinator(textual content: $textual content, placeHolder: placeHolder, peak: $peak, selectedText: $selectedText, selectedTextRange: $selectedTextRange)
}
class Coordinator: NSObject, GrowingTextViewDelegate {
@Binding var textual content: String
var placeHolder: String
@Binding var peak: CGFloat
@Binding var selectedText: String
@Binding var selectedTextRange: UITextRange?
non-public var tempSelectedBodyTextRange: UITextRange? = nil
init(textual content: Binding<String>, placeHolder: String, peak: Binding<CGFloat>, selectedText: Binding<String>, selectedTextRange: Binding<UITextRange?>) {
self._text = textual content
self.placeHolder = placeHolder
self._height = peak
self._selectedText = selectedText
self._selectedTextRange = selectedTextRange
}
func textViewDidChange(_ textView: UITextView) {
// UIKit -> SwiftUI
_text.wrappedValue = textView.textual content
}
func textViewDidChangeSelection(_ textView: UITextView) {
// Fires off each time the consumer adjustments the choice.
if let selectedText = textView.selectedText, let vary = textView.selectedTextRange {
DispatchQueue.essential.async { [weak self] in
guard let self = self else { return }
self._selectedText.wrappedValue = selectedText
self._selectedTextRange.wrappedValue = vary
self.tempSelectedBodyTextRange = vary
}
//print(selectedText)
}
}
func textViewDidChangeHeight(_ textView: GrowingTextView, peak: CGFloat) {
DispatchQueue.essential.async {
self.peak = peak
}
}
func textViewDidEndEditing(_ textView: UITextView) {
// Save the chosen vary when the textual content view ends enhancing
if let vary = tempSelectedBodyTextRange {
DispatchQueue.essential.async {
self._selectedTextRange.wrappedValue = vary
textView.selectedTextRange = vary
}
}
}
}
}
struct TextSelectedView: View {
@State non-public var textual content = ""
@State non-public var selectedText = ""
@State non-public var selectedTextRange: UITextRange? = nil
var physique: some View {
GrowingTextViewRepresentable(placeHolder: "Place holder", customFont: .systemFont(ofSize: 12), placeHolderColor: .lightGray, textColor: .black, textual content: $textual content, peak: .fixed(50), selectedText: $selectedText, selectedTextRange: $selectedTextRange)
}
}
struct TextSelectedView_Previews: PreviewProvider {
static var previews: some View {
TextSelectedView()
}
}
extension UITextView {
var selectedText: String? {
guard let selectedRange = selectedTextRange else { return nil }
return textual content(in: selectedRange)
}
}
How I am utilizing it:
import UIKit
struct MyView: View {
@State non-public var physique:String = ""
@State non-public var selectedBodyText: String = ""
@State non-public var selectedBodyTextRange: UITextRange? = nil
@State non-public var heightOfBody: CGFloat = 0
var physique: some View {
GrowingTextViewRepresentable(placeHolder: "write about...",
textual content: physique, peak: $heightOfBody, selectedText: selectedBodyText, selectedTextRange: selectedBodyTextRange)
.body(peak: heightOfBody)
.body(minHeight: 20)
.onChange(of: viewModel.selectedBodyText, carry out: { newValue in
print("selectedBodyText: (newValue)")
})
}
}
I tried to retain the worth in tempSelectedBodyTextRange after which reset it in textViewDidEndEditing, nevertheless it did not work as anticipated.