1

I have issues calculating the accurate size of a NSString displayed in a UITextField.

My goal is to update the textfield frame size according to the string size programmatically (without using sizeToFit). I am using the sizeWithFont function.

-(void)resizeTextFieldAccordingToText:(NSString*)textFieldString {

    CGPoint originalCenter = self.textField.center;

    UIFont* currentFont = [textField font];
    CGSize newSize = [textFieldString sizeWithFont:currentFont];

    //Same incorrect results with the extended version of sizeWithFont, e.g.
    //[textFieldString sizeWithFont:currentFont constrainedToSize:CGSizeMake(300.0, 100.0) lineBreakMode:NSLineBreakByClipping];

    [self.textField setFrame:(CGRectMake(self.textField.frame.origin.x, self.textField.frame.origin.y, newSize.width, newSize.height))];
    [self.textField setCenter:originalCenter];

} 

Problem: While this return correct size results at first its becomes more and more unprecise by adding characters therefore finally starts clipping the string (as seen in the right screenshot).

enter image description here

How do I get the accurate size of the textField string for correctly adjusting its size?

Bernd
  • 11,133
  • 11
  • 65
  • 98
  • May be this post could be useful for your purposes: http://stackoverflow.com/questions/1435544/measuring-the-pixel-width-of-a-string – RFG Oct 19 '13 at 09:35
  • I am aware of this but even using this extended version of sizeWithFont (e.g. CGSize newSize = [textFieldString sizeWithFont:currentFont constrainedToSize:CGSizeMake(300.0, 100.0) lineBreakMode:NSLineBreakByClipping];) does return the same slightly incorrect sizes. – Bernd Oct 19 '13 at 09:38
  • yes, because it doesn't account for padding – Daij-Djan Oct 19 '13 at 09:46
  • When are you resizing your text field? Remember that the delegate method `-textField:shouldChangeCharactersInRange:replacementString:` gets called _before_ the text field's text actually changes, so if you calculate your new size there, you need to build the modified text using `NSString`'s `-stringByReplacingCharactersInRange:withString:`. Otherwise, your size will always be one character "late". – Nicolas Miari Nov 17 '15 at 02:27

2 Answers2

1

the problem is that you don't take into account the contentInset of the UITextField. Your code would be fine for a label not for a textfield.

for example: one way could be:

CGPoint originalCenter = self.textField.center;

UIFont* currentFont = [textField font];
CGSize oldSize = [self.textField.text sizeWithFont:currentFont];
CGSize newSize = [textFieldString sizeWithFont:currentFont];

CGRect finalFrame = self.textField.frame
finalFrame.size.width -= oldSize.width;
finalFrame.size.width += newSize.width;
finalFrame.size.height -= oldSize.height;
finalFrame.size.height += newSize.height;
[self.textField setFrame:finalFrame];

[self.textField setCenter:originalCenter];

ios7 deprecates sizeWithFont:currentFont so it is sizeWithAttributes:@{NSFontAttributeName:currentFont}

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • written inline, not tested -- but the principles should become clear: the size isn't only that of the string – Daij-Djan Oct 19 '13 at 09:47
1

UITextField has it's own layout inside if you use borderStyle != UITextBorderStyleNone. In this case you have to increase text size dimensions by some constants.

With UITextBorderStyleNone you don't have this problem, and code below works like a charm (iOS 7 introduced new method to get text size, -sizeWithFont: is deprecated)

- (IBAction)textChanged:(UITextField *)field
{
    UIFont *font = field.font;
    NSString *string = field.text;

    CGSize size = [string sizeWithAttributes:
            [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]];

    CGPoint center = field.center;
    CGRect frame = field.frame;
    frame.size = size; // or CGSizeMake(size.width + WIDTH_PADDING * 2, size.height + HEIGHT_PADDING * 2)
    field.frame = frame;
    field.center = center;
}
LorikMalorik
  • 2,001
  • 1
  • 14
  • 14
  • Unfortunately the problem remains. A static padding doesn't help. I would need to adjust the padding with every string change because the precision of sizeWithFont changes with each character changed. – Bernd Oct 19 '13 at 10:06
  • Which font do you use? I have tried several standard fonts - no clipping, everything seems to be ok – LorikMalorik Oct 19 '13 at 10:17
  • Hmm. That's puzzling. In my example I used a non-system font (font-family: "SourceSansPro-ExtraLight"; font-weight: normal; font-style: normal; font-size: 38.00pt). However when I use the default font (font-family: ".HelveticaNeueInterface-M3"; font-weight: normal; font-style: normal; font-size: 17.00pt) I have the very same issue. – Bernd Oct 19 '13 at 11:07
  • in my answer I address the same issue but I don't care about what border style is used. – Daij-Djan Oct 19 '13 at 11:48
  • still - this sounds reasonable when you have NO border. I dislike constants :D – Daij-Djan Oct 19 '13 at 11:49