9

问题:在某些情况下UITextView默默地改变它。contentSize

最简单的文本视图,带有大文本和键盘。只需添加 UITextView 插座并设置- viewDidLoad为:

- (void)viewDidLoad {
    [super viewDidLoad];
    // expand default "Lorem..."
    _textView.text = [NSString stringWithFormat:@"1%@\n\n2%@\n\n3%@\n\n4%@\n\n5", _textView.text, _textView.text, _textView.text, _textView.text];
    _textView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
    _textView.contentInset = UIEdgeInsetsMake(0, 0, 216, 0);
}

现在显示和隐藏键盘在某些情况下会导致文本跳转。

我找到了按 subclass 跳转的原因UITextView。我的子类中唯一的方法是:

- (void)setContentSize:(CGSize)contentSize {
    NSLog(@"CS: %@", NSStringFromCGSize(contentSize));
    [super setContentSize:contentSize];
}

它显示contentSize缩小和扩大键盘隐藏。像这样的东西:

013-09-16 14:40:27.305 textView-bug2[11087:a0b] CS: {320, 651}
2013-09-16 14:40:27.313 textView-bug2[11087:a0b] CS: {320, 885}
2013-09-16 14:40:27.318 textView-bug2[11087:a0b] CS: {320, 902}

看起来UITextViewiOS7 中的行为发生了很大变化。现在有些东西坏了。

进一步发现我发现layoutManager我的 textView 的新属性也发生了变化。现在日志中有一些有趣的信息:

2013-09-16 14:41:59.352 textView-bug2[11115:a0b] CS: {320, 668}
<NSLayoutManager: 0x899e800>
    1 containers, text backing has 2129 characters
    Currently holding 2129 glyphs.
    Glyph tree contents:  2129 characters, 2129 glyphs, 3 nodes, 96 node bytes, 5440 storage bytes, 5536 total bytes, 2.60 bytes per character, 2.60 bytes per glyph
    Layout tree contents:  2129 characters, 2129 glyphs, 532 laid glyphs, 13 laid line fragments, 4 nodes, 128 node bytes, 1048 storage bytes, 1176 total bytes, 0.55 bytes per character, 0.55 bytes per glyph, 40.92 laid glyphs per laid line fragment, 90.46 bytes per laid line fragment

下一行 contentSize = {320, 885}contains Layout tree contents: ..., 2127 laid glyphs, 51 laid line fragments。所以看起来某种自动布局试图在键盘显示上重新布局 textView 并更改 contentSize,即使布局尚未完成。即使我的 textView 在键盘显示/隐藏之间没有变化,它也会运行。

问题是:如何防止 contentSize 发生变化?

4

3 回答 3

7

看起来问题出在默认的 layoutManager 中UITextView。我决定对它进行子类化,看看在哪里以及为什么开始重新布局。但是使用默认设置的简单创建NSLayoutManager解决了这个问题。

这是我的演示项目中的代码(不完美)(见问题)。有_textView一个插座,所以我将其从 superview 中删除。此代码位于- viewDidLoad

NSTextStorage* textStorage = [[NSTextStorage alloc] initWithString:_textView.text];
NSLayoutManager* layoutManager = [NSLayoutManager new];
[textStorage addLayoutManager:layoutManager];
_textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size];
[layoutManager addTextContainer:_textContainer];
[_textView removeFromSuperview];    // remove original textView
_textView = [[MyTextView alloc] initWithFrame:self.view.bounds 
                                textContainer:_textContainer];
[self.view addSubview:_textView];

MyTextView这是 的子类UITextView,详情请参阅问题。

有关更多信息,请参阅:

于 2013-09-19T19:12:57.587 回答
1

我遇到了与urs类似的情况。我的显示有不同的错误,但由于相同的原因:iOS7 不正确地更改了 contentSize 属性。这是我解决它的方法。它有点丑陋的修复。每当我需要使用 textView.contentSize 时,我都会自己计算。

-(CGSize)sizeOfText:(NSString *)textToMesure widthOfTextView:(CGFloat)width withFont:(UIFont*)font
{
    CGSize size = [textToMesure sizeWithFont:font constrainedToSize:CGSizeMake(width-20.0, FLT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
    return size;
}

那么你可以调用这个函数来获取大小:

CGSize cont_size =   [self sizeOfText:self.text widthOfTextView:self.frame.size.width withFont:[UIFont systemFontOfSize:15]];

然后,不要执行以下操作:

self.contentSize = cont_size;// it causes iOS halt occasionally.

所以,直接使用 cont_size 即可。 我相信它现在是iOS7中的错误。希望苹果能尽快修复它。希望这会有所帮助。

于 2013-10-01T10:06:53.187 回答
1

似乎是iOS7中的错误。在 iOS7 中,输入文本内容区域的行为是有线的,它适用于较低的 iOS7 版本。

我在下面添加了 UITextView 的委托方法来解决这个问题:

- (void)textViewDidChange:(UITextView *)textView {
CGRect line = [textView caretRectForPosition:
    textView.selectedTextRange.start];
CGFloat overflow = line.origin.y + line.size.height
    - ( textView.contentOffset.y + textView.bounds.size.height
    - textView.contentInset.bottom - textView.contentInset.top );
if ( overflow > 0 ) {
// We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
// Scroll caret to visible area
    CGPoint offset = textView.contentOffset;
    offset.y += overflow + 7; // leave 7 pixels margin
// Cannot animate with setContentOffset:animated: or caret will not appear
    [UIView animateWithDuration:.2 animations:^{
        [textView setContentOffset:offset];
    }];
}
于 2013-10-23T12:36:38.933 回答