I'm struggling with this seems to be simple problem, but have not found the good fix yet:
I have a NSTextView inside NSScrollView, textView is non-editable, the whole textView stringValue is replaced after every 2s.
It works fine when the textView height is less than scrollView height, but when it's longer then the scrollView will always automatically scroll back to top after each text replace. I'd want it to keep the same offset after update.
My current implement, it works but it flickering due to manual scrolling, hope to find a way that can keep the offset without flickering, not sure if there's any config that can do it:
CGFloat offset = self.scrollView.documentVisibleRect.origin.y;
self.newText = .....; // Update the textView string via binding
if (offset > 0) {
CGFloat maxHeight = fabs(self.scrollView.documentView.frame.size.height - self.scrollView.frame.size.height) + 2;
dispatch_async(dispatch_get_main_queue(), ^{
[self.scrollView.documentView scrollPoint:CGPointMake(0, MIN(offset, maxHeight))];
});
}
After checking some similar iOS question, I found a way to do this, the point is not replacing the text using binding or set it via textView.string
:
NSRange selectedRange = self.textView.selectedRange;
[self.textView.textStorage beginEditing];
NSRange rangeToReplace = NSMakeRange(0, self.textView.textStorage.string.length);
[self.textView.textStorage replaceCharactersInRange:rangeToReplace withString:newText];
[self.textView.textStorage endEditing];
// This is to keep the selected text
if(selectedRange.location != NSNotFound && NSMaxRange(selectedRange) <= rangeToReplace.length) {
[self.textView setSelectedRange:NSMakeRange(selectedRange.location, selectedRange.length)];
}