Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITextView contentOffset on iOS 7

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)...

like image 720
Mihai Avatar asked Oct 01 '13 11:10

Mihai


3 Answers

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];
like image 125
Mihai Avatar answered Oct 12 '22 11:10

Mihai


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.

like image 23
vidonism Avatar answered Oct 12 '22 11:10

vidonism


@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.

like image 27
race_carr Avatar answered Oct 12 '22 10:10

race_carr