Waiting for UITextView to Finish Updating Text (iO

2019-06-14 01:51发布

问题:

I'm programatically updating the attributedText of a UITextView. Following the update I want to call setContentOffset so that I can scroll to position the new text.

The problem I'm having is that there's a delay in the text view updating its text.

With the following code the debug log outputs the same value:

- (void)appendToTextView:(NSString*)text
{
    CGFloat bottomOfCurrentContent = _pastedText.contentSize.height;
    NSLog(@"Bottom of content, before = %f", bottomOfCurrentContent);

    NSString* textViewText = text;

    BOOL previouslyHadText = _pastedText.text.length > 0;
    if (previouslyHadText) {
        textViewText = [NSString stringWithFormat:@"%@\n%@", _pastedText.text, textViewText];
    }

    NSMutableParagraphStyle* paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineSpacing = _lineSpacing;
    NSDictionary *attribute = @{ NSParagraphStyleAttributeName : paragraphStyle,
                                 NSFontAttributeName : [UIFont systemFontOfSize:18.0] };

    _pastedText.attributedText = [[ NSAttributedString alloc] initWithString:textViewText attributes:attribute];

    if (previouslyHadText) {
        CGFloat bottomOfNewContent = _pastedText.contentSize.height;
        NSLog(@"Bottom of content, after = %f", bottomOfNewContent);
        // Set content offset...
    }
}

E.g., output:

2014-05-03 21:52:57.181 thisApp[7011:60b] Bottom of content, before = 244.000000
2014-05-03 21:52:57.182 thisApp[7011:60b] Bottom of content, after = 244.000000

If I artificially wait for the text view to complete its update the content is reported as expected...

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        CGFloat bottomOfNewContent = _pastedText.contentSize.height;
        NSLog(@"Bottom of content, after = %f", bottomOfNewContent);
        // Set content offset...
    });

Output:

2014-05-03 23:12:39.694 thisApp[7050:60b] Bottom of content, before = 244.000000
2014-05-03 23:12:44.698 thisApp[7050:60b] Bottom of content, after = 451.000000

So, how do I get updated when the UITextViews update has finished?

Update:

Based on the suggestion from indyfromoz, I can get a callback from the delegate method textViewDidChangeSelection, following a programatic update to the text view. However, when that delegate method is called, the text view still hasn't finished updating.

If I drop the log statement in there:

- (void)textViewDidChangeSelection:(UITextView *)textView
{    
    CGFloat newContentHeight = textView.contentSize.height;
    NSLog(@"bottom of new content: %f", newContentHeight);
}

The content height is reported the same as it was before the update...

I'm putting this down to a bug with UITextView. I'll work around it for now and look at the code again in the future.

回答1:

After the insertion of the new text in your UITextView, you can use scrollRangeToVisible (Typically through the textViewDidChangeSelection delegate method) to scroll the text view's content. UITextView in iOS 7 has some bugs and there is a good article by Peter discussing this and Brent Simmons has a near perfect solution for scrolling content in UITextView.