7

当键盘显示时,我一直在我的视图控制器中使用以下代码来更新 UITextView 的内容偏移量:

- (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;
}

随着键盘的显示,手动将 UITextView 的内容滚动到底部使其正确地结束在键盘顶部的上方。-[UITexView scrollRangeToVisible:] 但是,似乎不再考虑键盘的存在。

  • 在 iOS 6 中,文本视图滚动直到指定范围显示在键盘上方。
  • 在 iOS 7 中,可见性现在似乎基于文本视图的框架,而不是像以前那样基于内容插入。所以视图只会在范围延伸到框架下方时滚动,然后它只会滚动到足以让该范围在底部可见

从视觉上看,这就是正在发生的事情。我为我的文本视图构建了一个内联搜索,其中包含在结果之间跳转的控件(类似于在 Safari 中搜索)。因此,在此处显示的带有搜索结果的文本视图中,当用户点击“下一步”按钮时,青色选择将向下循环显示结果。当用户转到第七个结果时,视图将滚动直到它可见。

当用户转到第五个搜索结果时,键盘(来自 UISearchBar)在相同的搜索结果上,它会滚动到键盘上方。但仅在 iOS 6 中。在 iOS 7 中,直到进入第七个搜索结果才会发生滚动,就像在非键盘情况下一样,即使这样它也会滚动相同的量,因此它仅在文本视图框架的底部下方可见。

这是 iOS 7 中已知的变化吗?我正在使用自动布局,所以接下来我要尝试的是调整文本视图的底部间距约束以缩小整个视图以避免问题,但想检查是否有办法仍然使用我现有的代码IOS 7。

4

2 回答 2

5

尽管这已经得到解答,但我在构建自己的UITextView带有搜索突出显示的子类时遇到了同样的问题(如果您感兴趣,它可以在我的 GitHub 上找到scrollRangeToVisible:)并提出了该方法的自定义实现。您需要做的就是按照您已经在做的那样调整您的contentInsetscrollIndicatorInset属性(阅读本文的普通 Google 员工的相关答案),然后致电:UITextView

[textView scrollRangeToVisible:range consideringInsets:YES];

我将相关代码封装在一个类别中,该类别还有一些其他有用的方法来解释 iOS 7 中的插入:

注意:由于我在子类中组织此代码的方式,您都需要它们。随意根据自己的喜好重新组织它。

@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
于 2013-11-08T20:27:08.433 回答
3

这似乎是iOS7中的一个错误。我正在使用以下代码作为解决方法(很大程度上受到以下问题的答案的启发:How to re-size UITextView when keyboard 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];
}

奇怪的是,在最后一次调用中无法将动画更改为 YES。

我将向 Apple 提交错误报告。

于 2013-10-13T13:12:44.447 回答