Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the NSRange for the visible text after scroll in UITextView

I'm trying to save the location of scrolled text in a UITextView so that I can return to that location upon loading the ViewController again. I have very long strings, so I want the user to be able to scroll to a specific location and then return to that location later.

I'm using the UITextView. scrollRangeToVisible function to automatically scroll the text view, but I don't know how to get the NSRange of the text that the user is seeing. Is this the best way to go about this? I tried using the setContentOffset function but that didn't seem to do anything.

Any help is appreciated. Thanks!

like image 616
L.EXE Avatar asked Oct 24 '25 14:10

L.EXE


1 Answers

Here's a little extension on UITextView that uses its characterRange(at:) function instead. It also adds a computed property to return the currently visible text:

extension UITextView {

    private var firstVisibleCharacterPosition: UITextPosition? {
        // ⚠️ For some reason `characterRange(at:)` returns nil for points with a low y value.
        guard let scrolledPosition = characterRange(at: contentOffset)?.start else {
            return beginningOfDocument
        }
        return scrolledPosition
    }

    private var lastVisibleCharacterPosition: UITextPosition? {
        return characterRange(at: bounds.max)?.end
    }

    /// The range of the text that is currently displayed within the text view's bounds.
    var visibleTextRange: UITextRange? {

        guard
            let first = firstVisibleCharacterPosition,
            let last = lastVisibleCharacterPosition else {
                return nil
        }

        return textRange(from: first, to: last)
    }      

    /// The string that is currently displayed within the text view's bounds.
    var visibleText: String? {
        guard let visibleTextRange = visibleTextRange else {
            return nil
        }
        return text(in: visibleTextRange)
    }

}

I used these shorthand properties in the code above:

extension CGRect {

    var min: CGPoint {
        return .init(x: minX, y: minY)
    }

    var max: CGPoint {
        return .init(x: maxX, y: maxY)
    }

}
like image 195
Mischa Avatar answered Oct 26 '25 03:10

Mischa