Tuesday, February 6, 2024
HomeiOS Developmentios - The right way to preserve the selectedTextRange in a UITextView...

ios – The right way to preserve the selectedTextRange in a UITextView UIViewRepresentable, it ought to stay chosen even after the main focus shifts to a different TextField


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.



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments