what to use instead of scrollRangeToVisible in iOS

2019-02-16 21:01发布

问题:

In previous versions of iOS, my UITextView will scroll to the bottom using

[displayText scrollRangeToVisible:NSMakeRange(0,[displayText.text length])];

or

CGFloat topCorrect = displayText.contentSize.height -[displayText bounds].size.height;
topCorrect = (topCorrect<0.0?0.0:topCorrect);
displayText.contentOffset = (CGPoint){.x=0, .y=topCorrect};

But the former will now have the weird effect of starting at the top of a long length of text and animating the scroll to the bottom each time I append text to the view. Is there a way to pop down to the bottom of the text when I add text?

回答1:

textView.scrollEnabled = NO;
[textView scrollRangeToVisible:NSMakeRange(textView.text.length - 1,0)];
textView.scrollEnabled = YES;

This really works for me in iOS 7.1.2.



回答2:

For future travelers, building off of @mikeho's post, I found something that worked wonders for me, but is a bit simpler.

1) Be sure your UITextView's contentInsets are properly set & your textView is already firstResponder() before doing this.
2) After my the insets are ready to go, and the cursor is active, I call the following function:

private func scrollToCursorPosition() {
    let caret = textView.caretRectForPosition(textView.selectedTextRange!.start)
    let keyboardTopBorder = textView.bounds.size.height - keyboardHeight!

   // Remember, the y-scale starts in the upper-left hand corner at "0", then gets
   // larger as you go down the screen from top-to-bottom. Therefore, the caret.origin.y
   // being larger than keyboardTopBorder indicates that the caret sits below the
   // keyboardTopBorder, and the textView needs to scroll to the position.
   if caret.origin.y > keyboardTopBorder {
        textView.scrollRectToVisible(caret, animated: true)
    }
 }


回答3:

I believe this is a bug in iOS 7. Toggling scrollEnabled on the UITextView seems to fix it:

[displayText scrollRangeToVisible:NSMakeRange(0,[displayText.text length])];
displayText.scrollEnabled = NO;
displayText.scrollEnabled = YES;


回答4:

I think your parameters are reversed in NSMakeRange. Location is the first one, then how many you want to select (length).

NSMakeRange(0,[displayText.text length])

...would create a selection starting with the 0th (first?) character and going the entire length of the string. To scroll to the bottom you probably just want to select a single character at the end.

This is working for me in iOS SDK 7.1 with Xcdoe 5.1.1.

[textView scrollRangeToVisible:NSMakeRange(textView.text.length - 1,0)];
textView.scrollEnabled = NO;
textView.scrollEnabled = YES;

I do this as I add text programmatically, and the text views stays at the bottom like Terminal or command line output.



回答5:

The best way is to set the bounds for the UITextView. It does not trigger scrolling and has an immediate effect of repositioning what is visible. You can do this by finding the location of the caret and then repositioning:

- (void)userInsertingNewText {
    UITextView *textView;
    // find out where the caret is located
    CGRect caret = [textView caretRectForPosition:textView.selectedTextRange.start];
    // there are insets that offset the text, so make sure we use that to determine the actual text height
    UIEdgeInsets textInsets = textView.textContainerInset;
    CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;
    // only set the offset if the caret is out of view
    if (textViewHeight < caret.origin.y) {
        [self repositionScrollView:textView newOffset:CGPointMake(0, caret.origin.y - textViewHeight)];
    }
}

/**
 This method allows for changing of the content offset for a UIScrollView without triggering the scrollViewDidScroll: delegate method.
 */
- (void)repositionScrollView:(UIScrollView *)scrollView newOffset:(CGPoint)offset {
    CGRect scrollBounds = scrollView.bounds;
    scrollBounds.origin = offset;
    scrollView.bounds = scrollBounds;
}