ios - iOS7 中UITextView contentSize 的变化和NSLayoutManager

标签 ios uitextview ios7 nslayoutmanager

问题:UITextView 在某些情况下悄悄地改变了它的 contentSize

最简单的情况是带有大文本和键盘的 textView。只需添加 UITextView socket 并将 - 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);
}

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

我找到了子类 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}

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

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

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} 的下一行包含Layout tree contents: ..., 2127 layed glyphs, 51 layed line fragments。所以看起来某种自动布局试图在键盘显示上重新布局 textView 并更改 contentSize 即使布局尚未完成。即使我的 textView 在键盘显示/隐藏之间没有变化,它也会运行。

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

最佳答案

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

这是我的演示项目(见问题)中的代码(不完美)。 _textView 有一个 socket ,所以我将它从 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 的子类,详见问题。

有关详细信息,请参阅:

关于ios - iOS7 中UITextView contentSize 的变化和NSLayoutManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18826199/

相关文章:

ios - Swift - Xcode 8.3 自动完成不显示

iOS 模拟器 : could not hardlink copy. 我的文件系统中的路径错误?

iphone - 扩展 UITextView

ios - UITableViewCell 没有出现在 iOS 7 中

objective-c - 求iOS6和iOS7动画表现差异的解释

ios - Xcode 6.4 只显示只运行 iPhone 6 模拟器

ios - UI 在连接到新 View Controller 时不会改变

ios - 如何使用 segue 将字符串传递给 textView?

ios - iOS7 上的 UITextView contentOffset 未使用 CGPointZero 初始化

ios - 将应用背景图片扩展到导航栏和状态栏