簡體   English   中英

UITextView contentSize更改和iOS7中的NSLayoutManager

[英]UITextView contentSize changes and NSLayoutManager in iOS7

問題:在某些情況下, UITextView默默地更改它的contentSize

最簡單的案例textView與大文本和鍵盤。 只需添加UITextView outlet並將- 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中發生了很大變化。 有些事情現在已經破裂了。

進一步發現我發現layoutManagerlayoutManager屬性也發生了變化。 現在日志中有一些有趣的信息:

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 laid glyphs, 51 laid line fragments 所以看起來某種autolayout試圖在鍵盤上重新布局textView並改變contentSize,即使布局還沒有完成。 即使我的textView在鍵盤顯示/隱藏之間沒有變化,它也會運行。

問題是:如何防止contentSize更改?

看起來問題出在UITextView默認layoutManager中。 我已經決定對它進行子類化,並查看重新布局的啟動位置和原因。 但是使用默認設置簡單創建NSLayoutManager解決了這個問題。

這是我的演示項目中的代碼(不完美)(參見問題)。 _textView有一個插座,所以我從_textView刪除它。 此代碼放在- 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];

這里的MyTextViewUITextView的子類,詳見問題。

有關詳情,請參閱:

我遇到了類似的情況。 我的節目有不同的錯誤,但由於同樣的原因: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中的錯誤。 希望蘋果能盡快修復它。 希望這是有幫助的。

似乎是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];
    }];
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM