Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Discrepancy between sizeWithFont:constrainedToSize:lineBreakMode: and textView.contentSize.height

I am using the method [string sizeWithFont:constrainedToSize:lineBreakMode:] to estimate the height of a textView that I am resizing. However, it seems to consistently return the incorrect size. To debug, I wrote the following code:

self.textView.font = [UIFont systemFontOfSize:14.0]; // It was this before, anyways
NSLog(@"Real width: %lf %lf", self.textView.contentSize.width, self.textView.frame.size.width);
NSLog(@"Real height: %lf", self.textView.contentSize.height);
NSLog(@"Estimated width: %lf", kOTMessageCellTextWidth);
NSLog(@"Estimated height: %lf", ([message.message sizeWithFont:[UIFont systemFontOfSize:14.0]
                                             constrainedToSize:CGSizeMake(kOTMessageCellTextWidth, CGFLOAT_MAX)
                                                 lineBreakMode:UILineBreakModeWordWrap].height));

However, the above code reveals that I am getting inconsistent results:

Real width: 223.000000 223.000000
Real height: 52.000000
Estimated width: 223.000000
Estimated height: 36.000000
Real width: 223.000000 223.000000
Real height: 142.000000
Estimated width: 223.000000
Estimated height: 126.000000
Real width: 223.000000 223.000000
Real height: 142.000000
Estimated width: 223.000000
Estimated height: 126.000000

I noticed in this similar question that (apparently) textView has some padding that constrains its actual width. The recommendation there was the decrease the width passed to sizeWithFont: by some number. The recommended number was 11.

My question: is there any way to actually retrieve this value programmatically, or is there some documentation that I missed specifying this number? It seems like this number should be available and shouldn't have to be guess-and-checked, but I can't find a reliable way to identify it.

Thanks in advance.

like image 539
Ashoat Avatar asked Dec 17 '22 22:12

Ashoat


2 Answers

OK, after a bit of (re)search, I've come to this.

UITextView has 8px of padding on each side. But also line-height is not the same with UILabel (and sizeWithFont methods' result)

in my case the font was Arial and the size was 16pt and line heights of textview is 4.5points more than uilabel's line heights. So;

  • I get the result (cSize) from sizeWithFont method, with giving width reduced by 16 pixels
  • I calculated the lineCount by cSize.height / font.lineHeight
  • and used cSize.height + (lineCount * 4.5) + 16.0 as the final height for textview

code (not the exact code):

CGSize constraintSize = CGSizeMake(250.0 - 16.0, MAXFLOAT);
CGSize labelSize = [message.text sizeWithFont:[UIFont fontWithName:@"Arial" size:16.0] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
CGFloat lineCount = labelSize.height / [UIFont fontWithName:@"Arial" size:16.0].lineHeight;
CGFloat additional = lineCount * 4.5;       // for 16.0 pt Arial for now
return labelSize.height + additional + 16.0;    // TextView fix

I'm still having a little problems and do not like the way i solved it. But seems ok for this problem. And It would be great if someone comes with a reasonable solution for this.

like image 69
Furkan Mustafa Avatar answered Dec 28 '22 06:12

Furkan Mustafa


The fix is simple, since UITextView has 8px of padding on each side, so when you are calculating text's true size, you should minus this 16px padding (8px on double sides) first, then the result is right. Please see following code snippet:

// self.descView is an UITextView
// UITEXTVIEW_TEXT_PADDING is 8.0
CGSize constrainedSize = CGSizeMake(self.descView.contentSize.width-UITEXTVIEW_TEXT_PADDING*2, MAXFLOAT);
CGSize trueSize = [self.descView.text sizeWithFont:self.descView.font 
                                 constrainedToSize:constrainedSize 
                                     lineBreakMode:UILineBreakModeWordWrap];

CGSize contentSize = self.descView.contentSize;
contentSize.height = trueSize.height;
self.descView.contentSize = contentSize;

frame = self.descView.frame;
frame.size.height = contentSize.height ;
self.descView.frame = frame;

The result should be right.

like image 21
Chengjiong Avatar answered Dec 28 '22 08:12

Chengjiong