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?
}
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)
}