Home > OS >  How to get selected range from UIViewRepresentable delegate method of UITextView in SwiftUI
How to get selected range from UIViewRepresentable delegate method of UITextView in SwiftUI

Time:10-31

I have a code and I need to get the selected range of TextView from (func textViewDidChangeSelection) to the ContentView. How do I do such a thing in SwiftUI?

this is a basic idea of my code.

struct ContentView: View {
    @State private var text = ""
    
    var body: some View {
        UITextViewRepresentable(text: $text)
    }
}

struct UITextViewRepresentable: UIViewRepresentable {
    let textView = UITextView()
    @Binding var text: String
    
    func makeUIView(context: Context) -> UITextView {
        textView.delegate = context.coordinator
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        // SwiftUI -> UIKit
        uiView.text = text
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(text: $text)
    }
    
    class Coordinator: NSObject, UITextViewDelegate {
        @Binding var text: String
        
        init(text: Binding<String>) {
            self._text = text
        }
        
        func textViewDidChange(_ textView: UITextView) {
            // UIKit -> SwiftUI
            _text.wrappedValue = textView.text
        }
        
        func textViewDidChangeSelection(_ textView: UITextView) {
            // Fires off every time the user changes the selection.
            print(textView.selectedRange)
        }
    }
}

CodePudding user response:

Just add an extra binding for it, of type NSRange, as that is the type of textView.selectedRange.

That means adding one to the UIViewRepresentable:

struct UITextViewRepresentable: UIViewRepresentable {
    let textView = UITextView()
    @Binding var text: String
    @Binding var range: NSRange // <---

and one to the coordinator:

func makeCoordinator() -> Coordinator {
    Coordinator(text: $text, range: $range) // <---
}

class Coordinator: NSObject, UITextViewDelegate {
    @Binding var text: String
    @Binding var range: NSRange // <---

    init(text: Binding<String>, range: Binding<NSRange>) {
        _text = text
        _range = range
    }

    // ...

    func textViewDidChangeSelection(_ textView: UITextView) {
        range = textView.selectedRange
    }

Now in ContentView, you can get it as a @State:

@State private var text = ""
@State private var range = NSRange()

var body: some View {
    UITextViewRepresentable(text: $text, range: $range)
}
  • Related