Search code examples
iosobjective-cios7storyboardxcode6

Why string formatting not work in UILabel?


How set all hyphens on same vertical position? I use next code:

subText = [NSString stringWithFormat:@"%3d%% - %@",subPercent,subfactor];
NSLog(@"%@",subText);
[label setText:subText];

But it's look like: https://i.sstatic.net/amei7.png

Labels created in storyboard and have left text alignment. App work on iOS 7+

Upd.

It's look mad, but work.

if (subPercent == 100) {
    subText = [NSString stringWithFormat:@"%d%% - %@",subPercent,subfactor];
} else if (subPercent > 9) {
    subText = [NSString stringWithFormat:@"  %d%% - %@",subPercent,subfactor];
} else {
    subText = [NSString stringWithFormat:@"    %d%% - %@",subPercent,subfactor];
}

Must be better solution.


Solution

  • The reason your numbers do not line up is that digits and spaces are different widths. However in many fonts, both fixed-width and proportional, all the digits are the same width and Unicode has a "figure space" character U+2007 which is a digit-width space. Unfortunately printf comes from pre-Unicode days and does not know about the figure space.

    However NSNumberFormatter is fully Unicode and localisation aware. To format an integer value between 0 and 100 as an NSString of 3 equal width characters you first define your formatter:

    NSNumberFormatter *formatter = [NSNumberFormatter new];
    formatter.numberStyle = NSNumberFormatterDecimalStyle;
    formatter.formatWidth = 3;
    formatter.paddingCharacter = @"\u2007"; // figure (digit) space
    

    and then use it to format you numbers:

    int value = 42; // a value between 0 -> 100
    NSString *formatted = [formatter stringFromNumber:@(value)];
    

    (note the @(...) which converts the int to an NSNumber).

    You can do better than this and have NSNumberFormatter format a floating point number between 0 and 1 as a percentage complete with the appropriate symbol for percent in the current locale. To do this set up the formatter using:

    NSNumberFormatter *formatter = [NSNumberFormatter new];
    formatter.numberStyle = NSNumberFormatterPercentStyle;
    formatter.formatWidth = 4; // 4 = 3 digits + percent symbol
    formatter.maximumFractionDigits = 0; // so we get a whole number (unless you want x.y%)
    formatter.paddingCharacter = @"\u2007"; // figure (digit) space
    

    If your value to format is an integer just divide it by 100.0:

    int value = 42; // a value between 0 -> 100
    NSString *formatted = [formatter stringFromNumber:@(value / 100.0)];
    

    Is this a "better solution"? You'll have to decide that and there are plenty of other ways.

    HTH

    (For fun: If you would like to stick with stringWithFormat consider what the base 10 log of an integer tells you about how many digits it has, and that you can print strings (think padding) with a variable field width - you can avoid your three-way if with a bit of math)