-scrollRangeToVisible: does not consider keyboard size in iOS 7

I used the following code in the view controller to update the offset of the contents of the UITextView when the keyboard is displayed:

- (void)keyboardWasShown:(NSNotification *)notification { NSDictionary *info = [notification userInfo]; CGRect keyboardRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; UIEdgeInsets contentInsets = UIEdgeInsetsMake( 0.0, 0.0, keyboardRect.size.height, 0.0 ); self.textView.contentInset = contentInsets; self.textView.scrollIndicatorInsets = contentInsets; } 

When the keyboard is displayed, manually scrolling the contents of the UITextView to the bottom of the screen, it ends just above the top of the keyboard. - [UITexView scrollRangeToVisible:], however, it seems to no longer account for the presence of the keyboard.

  • In iOS 6, the text view scrolls until the specified range is displayed just above the keyboard.
  • In iOS 7, visibility will now be based on the frame of the text view, and not on the insertion of content, as it was before. Thus, the view will scroll only when the range is below the frame, and then it will scroll only to get this range, visible at the bottom

Visually, this is what happens. I built a built-in search for my text view with controls to navigate between the results (similar to searching in Safari). Thus, in the text view shown here with the search results , when the user clicks the "Next" button, the blue selection will cycle through the results. When the user moves to the seventh result, the view will scroll until it becomes visible.

With the keyboard (from UISearchBar) up the same search results , when the user moves to the fifth search result, he will scroll just above the keyboard, but only in iOS 6. In iOS 7, scrolling does not happen until the transition to the seventh search result, for example, in a situation other than the keyboard, and even then it scrolls the same amount as it is visible below the bottom of the text presentation frame.

Is this a known change in iOS 7? I use auto-layout, so the next thing I’m going to try is to adjust the distance to the bottom level of the text to reduce the whole view, to avoid the problem, but I want to check if there is a way to use my existing code under iOS 7.

+6
source share
2 answers

Despite the fact that this has already been answered, I had the same problem when creating my own subclass of UITextView with search highlighting (a related answer is available for random Googlers reading this), then call:

 [textView scrollRangeToVisible:range consideringInsets:YES]; 

I wrapped the corresponding code in a category, which also has a couple of other useful methods for accounting for attachments in iOS 7:

Note: you need all of them because of how I organized this code in my subclass. Feel free to reorganize it to your liking.

 @interface UITextView (insets) // Scrolls to visible range, eventually considering insets - (void)scrollRangeToVisible:(NSRange)range consideringInsets:(BOOL)considerInsets; // Scrolls to visible rect, eventually considering insets - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated consideringInsets:(BOOL)considerInsets; // Returns visible rect, eventually considering insets - (CGRect)visibleRectConsideringInsets:(BOOL)considerInsets; @end @implementation UITextView (insets) // Scrolls to visible range, eventually considering insets - (void)scrollRangeToVisible:(NSRange)range consideringInsets:(BOOL)considerInsets { if (considerInsets && (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)) { // Calculates rect for range UITextPosition *startPosition = [self positionFromPosition:self.beginningOfDocument offset:range.location]; UITextPosition *endPosition = [self positionFromPosition:startPosition offset:range.length]; UITextRange *textRange = [self textRangeFromPosition:startPosition toPosition:endPosition]; CGRect rect = [self firstRectForRange:textRange]; // Scrolls to visible rect [self scrollRectToVisible:rect animated:YES consideringInsets:YES]; } else [self scrollRangeToVisible:range]; } // Scrolls to visible rect, eventually considering insets - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated consideringInsets:(BOOL)considerInsets { if (considerInsets && (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)) { // Gets bounds and calculates visible rect CGRect bounds = self.bounds; UIEdgeInsets contentInset = self.contentInset; CGRect visibleRect = [self visibleRectConsideringInsets:YES]; // Do not scroll if rect is on screen if (!CGRectContainsRect(visibleRect, rect)) { CGPoint contentOffset = self.contentOffset; // Calculates new contentOffset if (rect.origin.y < visibleRect.origin.y) // rect precedes bounds, scroll up contentOffset.y = rect.origin.y - contentInset.top; else // rect follows bounds, scroll down contentOffset.y = rect.origin.y + contentInset.bottom + rect.size.height - bounds.size.height; [self setContentOffset:contentOffset animated:animated]; } } else [self scrollRectToVisible:rect animated:animated]; } // Returns visible rect, eventually considering insets - (CGRect)visibleRectConsideringInsets:(BOOL)considerInsets { CGRect bounds = self.bounds; if (considerInsets) { UIEdgeInsets contentInset = self.contentInset; CGRect visibleRect = self.bounds; visibleRect.origin.x += contentInset.left; visibleRect.origin.y += contentInset.top; visibleRect.size.width -= (contentInset.left + contentInset.right); visibleRect.size.height -= (contentInset.top + contentInset.bottom); return visibleRect; } return bounds; } @end 
+5
source

This seems to be a bug in iOS7. I use the following code to work (heavily inspired by answers to the following questions: How to resize a UITextView when the keyboard is shown with iOS 7 ).

 CGRect caret_rect = [_editTextView caretRectForPosition:_editTextView.selectedTextRange.end]; UIEdgeInsets insets = _editTextView.contentInset; CGRect visible_rect = _editTextView.bounds; visible_rect.size.height -= (insets.top + insets.bottom); visible_rect.origin.y = _editTextView.contentOffset.y; if(!CGRectContainsRect(visible_rect, caret_rect)) { CGFloat new_offset = MAX((caret_rect.origin.y + caret_rect.size.height) - visible_rect.size.height - _editTextView.contentInset.top, - _editTextView.contentInset.top); [_editTextView setContentOffset:CGPointMake(0, new_offset) animated:NO]; } 

Oddly enough, it's impossible to change the animated value of YES in the last call.

I will write a bug report with Apple.

+3
source

Source: https://habr.com/ru/post/954692/


All Articles