10

I have a UITextView inside a UIScrollView that worked perfectly fine on iOS 6 built from xcode 4.x, however now building with xcode 5 it doesn't work properly, even on iOS 6.

The problem is the text wraps with the screen width even though the UITextView and UIScrollView have large widths. I use this code to work out the new width and height of the UITextView, and even though the textview scrolls left/right the text is wrapped as if the width is only the width of the screen.

Thanks

self.responceTextView.text = [NSString stringWithFormat:@"%@%@",_responceTextView.text,responce];
[self textViewDidChange:self.responceTextView];

- (void)textViewDidChange:(UITextView *)textView
{
    // Recalculate size of text field
    CGSize maxSize = CGSizeMake(MAXFLOAT, MAXFLOAT);
    CGSize reqSize = [textView.text sizeWithFont:[UIFont fontWithName:@"Courier" size:12] constrainedToSize:maxSize lineBreakMode:NSLineBreakByClipping];

    self.responceTextView.frame = CGRectMake(0, 0, reqSize.width+16, reqSize.height+16);

    // Resize scroll view if needs to be smaller so text stays at top of screen
    CGFloat maxScrollHeight = maxScrollViewSize.size.height;
    if (self.responceTextView.frame.size.height < maxScrollHeight) {
        self.responceScrollView.frame = CGRectMake(self.responceScrollView.frame.origin.x, self.responceScrollView.frame.origin.y, self.responceScrollView.frame.size.width, self.responceTextView.frame.size.height);
    } else {
        self.responceScrollView.frame = maxScrollViewSize;
    }

    // Set content size
    self.responceScrollView.contentSize = CGSizeMake(self.responceTextView.frame.size.width, self.responceTextView.frame.size.height);

    [self scrollToCursor];
}

EDIT ----

Ok, so it seems sizeWithFont is deprecated in iOS 7. Strange how I get no compiler warning. It still doesn't make sense that it doesn't work on iOS 6 (or is it completely removed when built with iOS 7 SDK?)

I have tried these 2 alternatives, but get exactly the same size back from all.

NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                [UIFont fontWithName:@"Courier" size:12], NSFontAttributeName,
                                nil];
CGRect rect = [textView.text boundingRectWithSize:maxSize options:NSLineBreakByClipping | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil];

returns: {{0, 0}, {439.27148, 168}}

CGSize rect2 = [textView.text sizeWithAttributes:attributes];

returns: {439.27148, 168}

And the original above returns {439.27148, 168}

They should all return a wider view.

EDIT 2 ---- It seems from above that the returned frame is correct (439 wide) however it's the text that is still being word wrapped inside the textview.

Darren
  • 10,182
  • 20
  • 95
  • 162
  • You're getting no warning on the iOS 7 deprecation because you're still building for iOS 6. It can't tell you to move to the new API, because the new one doesn't exist in one of your targets. And BTW it's "response" not "responce" :) – Graham Perks Sep 26 '13 at 13:19
  • 1
    I like to keep my code unique ;) – Darren Sep 26 '13 at 13:59

4 Answers4

18

try using:

[textView.text boundingRectWithSize:CGSizeMake(txtFrame.size.width, CGFLOAT_MAX)
                           options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                           attributes:[NSDictionary dictionaryWithObjectsAndKeys:textView.font,NSFontAttributeName, nil] context:nil];

The string measuring seems pretty buggy. This is the only option combination that gives the right size, for the testing I have done.

I'm using the following code with success in iOS7 (it's a UITextField with a minimum and maximum height. When the text's height get larger then MAX_HEIGHT_MESSAGE_TEXTBOX, scrollbars appears in the UITextField).

const float MAX_HEIGHT_MESSAGE_TEXTBOX = 80;
const float MIN_HEIGHT_MESSAGE_TEXTBOX = 30;


- (void)setFrameToTextSize:(CGRect)txtFrame textView:(UITextView *)textView
{

    if(txtFrame.size.height > MAX_HEIGHT_MESSAGE_TEXTBOX)
    {
        //OK, the new frame is to large. Let's use scroll
        txtFrame.size.height = MAX_HEIGHT_MESSAGE_TEXTBOX;
        textView.scrollEnabled = YES;
        [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)];
    }
    else
    {
        if (textView.frame.size.height < MIN_HEIGHT_MESSAGE_TEXTBOX) {
             //OK, the new frame is to small. Let's set minimum size
            txtFrame.size.height = MIN_HEIGHT_MESSAGE_TEXTBOX;
        }
        //no need for scroll
        textView.scrollEnabled = NO;
    }
    //set the frame
    textView.frame = txtFrame;
}

- (void)setframeToTextSize:(UITextView *)textView animated:(BOOL)animated
{
    //get current height
    CGRect txtFrame = textView.frame;

    //calculate height needed with selected font. Note the options.
    //append a new line to make space for the cursor after user hit the return key
    txtFrame.size.height =[[NSString stringWithFormat:@"%@\n ",textView.text]
                           boundingRectWithSize:CGSizeMake(txtFrame.size.width, CGFLOAT_MAX)
                           options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                           attributes:[NSDictionary dictionaryWithObjectsAndKeys:textView.font,NSFontAttributeName, nil] context:nil].size.height;

    if (animated) {
        //set the new frame, animated for a more nice transition
        [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut |UIViewAnimationOptionAllowAnimatedContent animations:^{
            [self setFrameToTextSize:txtFrame textView:textView];
        } completion:nil];
    }
    else
    {
        [self setFrameToTextSize:txtFrame textView:textView];
    }
}

- (void)textViewDidChange:(UITextView *)textView
{
    [self setframeToTextSize:textView animated:YES];
}

EDIT

When the string measuring is correct, you might need to change the lineBreakModeon the UITextView's textContainer. (NSTextContainer is a new class in iOS7, containing information about how text should be laid out):

textView.textContainer.lineBreakMode = NSLineBreakByCharWrapping; // default is NSLineBreakByWordWrapping 

Good luck!

EsbenB
  • 3,356
  • 25
  • 44
  • Thanks, but this doesn't seem to address my issue. I am using both flexible width and height. It seems like i'm getting the correct dimensions returned as the textview scrolls enough in both directions, however the text itself is still being wordwrapped. – Darren Sep 27 '13 at 10:03
  • Although I still didn't get to the bottom of this, I am awarding you the bounty so it doesn't go to waste. Thanks for trying. – Darren Sep 27 '13 at 14:01
  • Thanks. I just updated the answer with one additional thing you might want to try out... – EsbenB Sep 28 '13 at 08:27
2

method sizeWithFont:(UIFont *)font constrainedToSize ..." has been deprecated in iOS 7.

It would function properly.

Check out its alternate in iOS 7

Instance Method of NSString

-(CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:

(NSDictionary *)attributes context:(NSStringDrawingContext *)context

Check this answer out. Replacement for deprecated sizeWithFont: in iOS 7?

Community
  • 1
  • 1
Muhammad Idris
  • 2,138
  • 1
  • 13
  • 9
  • Thanks for that. Strange how I got no compiler warning. Please see my edit to the question. Thanks – Darren Sep 20 '13 at 09:32
0

I think you want to calculate the content size so that you can increase the content size of scroll view too. if yes Use this link, https://stackoverflow.com/a/19152955/1023083

Community
  • 1
  • 1
Shreesh Garg
  • 562
  • 5
  • 18
0

for response to "Thanks, but this doesn't seem to address my issue. I am using both flexible width and height. It seems like i'm getting the correct dimensions returned as the textview scrolls enough in both directions, however the text itself is still being wordwrapped."

I fixed this by [textView sizeToFit];