3

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?
   }
rdk
  • 439
  • 3
  • 14

1 Answers1

5

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)
}
Deyton
  • 2,364
  • 1
  • 15
  • 10