3

In this question I asked for a good way to truncate a string to fit a given UITextView. Since there was no way provided by the SDK directly, I've ended up writing the recursive method below (only called by the following public method). However, this doesn't work unless I subtract a fudge factor of 15 (kFudgeFactor) from the field width when calculating the string's height. If I don't do that, the string returned is actually too long for the field, and displays in an extra line below it. Anyone any idea why, and what I should really use instead of this fudge factor?

#pragma mark Size string to fit the new view

#define kFudgeFactor 15.0
#define kMaxFieldHeight 9999.0

// recursive method called by the main API
-(NSString*) sizeStringToFit:(NSString*)aString min:(int)aMin max:(int)aMax
{
if ((aMax-aMin) <= 1)
    {
    NSString* subString = [aString substringToIndex:aMin];
    return subString;
    }

int mean = (aMin + aMax)/2; 
NSString* subString = [aString substringToIndex:mean];

CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [subString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];

if (stringSize.height <= self.frame.size.height)
        return [self sizeStringToFit:aString min:mean max:aMax]; // too small
else    
        return [self sizeStringToFit:aString min:aMin max:mean];// too big
}

-(NSString*)sizeStringToFit:(NSString*)aString
{

CGSize tallerSize = CGSizeMake(self.frame.size.width-kFudgeFactor,kMaxFieldHeight);
CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];

// if it fits, just return
if (stringSize.height < self.frame.size.height)
    return aString; 

// too big - call the recursive method to size it       
NSString* smallerString = [self sizeStringToFit:aString min:0 max:[aString length]];
return smallerString;   
}
Community
  • 1
  • 1
Jane Sales
  • 13,526
  • 3
  • 52
  • 57
  • That's a good answer, but doesn't seem to be right. I'd already checked the contentInset of the scroll view, and that was 0. I just checked the difference between the frame's width and the scroll view's contentSize's width - and that's zero too. So it looks as though the UITextView is the whole width of the scroll view. – Jane Sales Jul 08 '09 at 13:03
  • I'm allowed to add comments now :-) Then it has to be an assumption by the linewrap code. If you do this without that mode, and just try to fit a single string, does it do the right thing? – drudru Jul 08 '09 at 17:40

2 Answers2

6

UIScrollView seems to use a fixed 8-pixel inset on both sides. This is independent of alignment or font size (based on testing & observation, not any explicit knowledge of the internals).

So it seems you are right to use your fudge factor, but it should probably be 16.0, not 15.0.

Frank Szczerba
  • 5,000
  • 3
  • 31
  • 31
  • Frank, I can't prove what you've said is right, but it seems so plausible after all I've tried to get to the root of this that I'm giving you the right answer. Why oh why doesn't Apple document stuff like this? Or give us the true width back in the text view's frame? – Jane Sales Jul 11 '09 at 13:56
  • I determined this by placing a text field in IB and overlapping another view until it just covered the text, then checking the positioning (using left-justified text when measuring the left margin and right-justified for the right margin). I then changed the font and font size and verified that the margins didn't change. – Frank Szczerba Jul 13 '09 at 02:15
  • @FrankSzczerba, just curious, how do you know "fudgeFactor = 16.0"? I believe this value should be smaller when text size is smaller – LiangWang May 01 '15 at 03:09
  • @Jacky - this was a long time ago and I haven't done iOS development for quite some time. Looking back on my older comments I think the 16.0 was the fixed padding added at the margins, independent of font size. That was probably under iOS 3. Things may have changed since then. – Frank Szczerba May 02 '15 at 17:51
0

This is probably because the frame of the UIView is not the same size as the content view. UITextView subclasses from UIScrollView.

drudru
  • 4,933
  • 1
  • 19
  • 19