rdk rdk - 3 months ago 31
iOS Question

Textview scrollRangeToVisible make range go to top

I am trying to scroll to a specific substring located in the attributedText of a UITextView. When the scrolling is complete, I want the substring to be located at the TOP of the visible textview text. However, I can only get the substring to go to the top when the textView.selectedRange is located below the range of the substring. How can I make it so the substring always appears at the top no matter where the scroll range was previously located?

This is my current code

let text = // a long NSAttributedString
let substring = "put me at the top!"
textView.attributedText = text

func scrollToSubstring() {
let str = text.string as NSString

let range = str.rangeOfString(substring, options: .RegularExpressionSearch, range: NSMakeRange(0, str.length), locale: nil)

textView.scrollRangeToVisible(range)
// HOW CAN I MAKE IT SO range ALWAYS APPEARS AT THE TOP?
}

Answer

UITextView is a UIScrollView subclass, so if you can find the substring's location in the scroll view's coordinates (possible using TextKit), then you can set the contentOffset accordingly. This is working for me:

func scrollSubstringToTop() {
    let str = text.string as NSString

    let substringRange = str.rangeOfString(substring)
    let glyphRange = textView.layoutManager.glyphRangeForCharacterRange(substringRange, actualCharacterRange: nil)
    let rect = textView.layoutManager.boundingRectForGlyphRange(glyphRange, inTextContainer: textView.textContainer)
    let topTextInset = textView.textContainerInset.top
    let contentOffset = CGPoint(x: 0, y: topTextInset + rect.origin.y)

    textView.setContentOffset(contentOffset, animated: true)
}