UITextView contentSize changes and NSLayoutManager in iOS7

后端 未结 3 1024
不思量自难忘°
不思量自难忘° 2021-02-06 04:20

The problem: UITextView silently changes it\'s contentSize in some situations.

The simplest case textView with large text and keyboard. Just ad

相关标签:
3条回答
  • 2021-02-06 04:40

    Looks like the problem is in default layoutManager of UITextView. I've decided to subclass it and see, where and why re-layout being initiated. But simple creation of NSLayoutManager with default settings solved the problem.

    Here is code (not perfect) from my demo project (see in question). The _textView there was an outlet, so I remove it from superview. This code is placed in - 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 here is a subclass of UITextView, see question for details.

    For more info see:

    • About Text Handling in iOS
    • Using Text Kit to Draw and Manage Text
    • NSLayoutManager Class Reference for iOS
    0 讨论(0)
  • 2021-02-06 04:50

    I met a similar situation as urs. Mine shows with a different bug but due to the same reason: the contentSize property is silently changed by iOS7 incorrectly. Here is how I work around it. Its kinda a ugly fix. Whenever I need to use textView.contentSize, I calculate it by myself.

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

    then you can just call this function to get the size:

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

    then, don't do the following:

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

    so, just use cont_size directly. I believe it's bug in iOS7 for now. Hopefully apple will fix it soon. Hope this is helpful.

    0 讨论(0)
  • 2021-02-06 04:50

    Seems the bug in iOS7. At the time of input text content area behavior is wired in iOS7, It works fine with lower iOS7 version.

    I have added below delegate method of UITextView to resolved this issue :

    - (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];
        }];
    }
    
    0 讨论(0)
提交回复
热议问题