UITextView contentOffset on iOS 7

2020-02-04 08:11发布

I have a UITextView in my app. I need to change it's content offset dynamically every time a new string is appended. The code bellow works fine on iOS 6 and earlier versions, but not on iOS 7.

CGPoint offset = CGPointMake(0, self.textView.contentSize.height - self.textView.frame.size.height);
[self.textView setContentOffset:bottomOffset animated:YES]; 

Do you have any ideas why?

Than you.

UPDATE

The UITextView doesn't set its contentOffset as it should, or something else mess it up. The result is not as expected (how it is on iOS 6 or earlier versions).

I've also tried setting the new property "textContainerInset" but still no results...

self.textView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0)    

UPDATE

As I can see in the didScroll delegate method, when I pass a positive value for content offset, it scrolls to (0,0). For example, I set the content offset to (0,35) and it scrolls to (0,0)...

6条回答
forever°为你锁心
2楼-- · 2020-02-04 08:19

The solution I've found is not elegant at all, but it works:

I set the UITextView's contentOffset to (0,0) before setting it to the desired offset. I don't know why this works, but for now is the best solution I've found.

CGPoint bottomOffset = CGPointMake(0, self.textView.contentSize.height - self.textView.frame.size.height);
[self.textView setContentOffset: CGPointMake(0,0) animated:NO]; 
[self.textView setContentOffset:bottomOffset animated:YES]; 
查看更多
成全新的幸福
3楼-- · 2020-02-04 08:23

I've had to resort to

[displayText scrollRangeToVisible:NSMakeRange([displayText.text length], 0)];

but the BIG problem with it is that it starts from the top of the text and scrolls to the end each time you append to the text. Mihai's solution also does that.

查看更多
三岁会撩人
4楼-- · 2020-02-04 08:26

I just noticed that today. In my case the issue is apparently related to the Text View being the first control in the view. I moved it to second place in the document outline (after a UILabel for example) and the offset is gone.

Most probably this is done on purpose because of the navigation bar new behaviour in iOS7.

查看更多
该账号已被封号
5楼-- · 2020-02-04 08:33

None of previous answers worked for me, because I had [textView setScrollEnabled:NO]. So, I ended up with this:

[textView setScrollEnabled:YES]
[self.text setContentOffset:CGPointMake(0, page * self.text.frame.size.height) animated:NO];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self.text setScrollEnabled:NO];
});
查看更多
别忘想泡老子
6楼-- · 2020-02-04 08:37

Ok, based on my research and other answers, the problem was the UITextView's content height and not the scrolling to a specific offset. Here is a solution that works the way it should work for iOS 7:

First, you need to recreate the UITextView like this:

    NSString *reqSysVer = @"7.0";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    BOOL osVersionSupported = ([currSysVer compare:reqSysVer  options:NSNumericSearch] != NSOrderedAscending);

    if (osVersionSupported) {

        NSLog(@"reset chatoutput");

        CGRect outputFrame = self.chatOutput.frame;

        [chatOutput removeFromSuperview];
        [chatOutput release];
        chatOutput = nil;

        NSTextStorage* textStorage = [[NSTextStorage alloc] init];
        NSLayoutManager* layoutManager = [NSLayoutManager new];
        [textStorage addLayoutManager:layoutManager];
        NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size];
        [layoutManager addTextContainer:textContainer];
        chatOutput = [[UITextView alloc] initWithFrame: outputFrame
                                           textContainer: textContainer];
        // if using ARC, remove these 3 lines
        [textContainer release];
        [layoutManager release];
        [textStorage release];

        [self.view addSubview: chatOutput];
    }

Then, use this method to get the UITextView content height:

- (CGFloat)textViewHeightForAttributedText:(NSAttributedString*)text andWidth:(CGFloat)width
{
     UITextView *calculationView = [[UITextView alloc] init];
     [calculationView setAttributedText:text];
     CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];

     NSLog(@"size: %f", size.height) ;

     return size.height;
}

Now you can set the content offset:

CGPoint bottomOffset;

bottomOffset = CGPointMake(0, [self textViewHeightForAttributedText: self.chatOutput.attributedText andWidth: self.chatOutput.frame.size.width] - self.chatOutput.frame.size.height);

[self.chatOutput setContentOffset:bottomOffset animated:YES];

UPDATE

I've read this in the Apple Documentation for NSAttributedString: "The default font for NSAttributedString objects is Helvetica 12-point, which may differ from the default system font for the platform."

In conclusion, if you use different fonts of different sizes, you have to set those to the NSAttributeString instance as well. Otherwise, the returned height won't correspond to your expectations. You may want to use something like this:

    NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject: [UIFont systemFontOfSize: 18.0] //or any other font or size
                                                                forKey: NSFontAttributeName];
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString: currentPost.postMessageText attributes: attrsDictionary];
    frame.size.height = [self textViewHeightForAttributedText: attributedString andWidth: 280.0];
    [attributedString release];
查看更多
家丑人穷心不美
7楼-- · 2020-02-04 08:37

@vidonism's answer works but this is even better.

// in -viewDidLoad of UIViewController
self.automaticallyAdjustsScrollViewInsets = NO;

See also top comment of accepted answer on this question. This likely explains the behavior of a UIScrollView being the first subView of a ViewController's main view.
I can't quite discren if this is expected behavior or a bug.

查看更多
登录 后发表回答