ManWithBear
ManWithBear

Reputation: 2875

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.

Upvotes: 1

Views: 223

Answers (4)

CRD
CRD

Reputation: 53000

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)

Upvotes: 1

rdelmar
rdelmar

Reputation: 104082

It seems that this problem has to do with the width of the space that's used for padding when you're not using a fixed width font. If you use a fixed width font like Courier, your code works ok (but courier is ugly). For a variable width font, I found that you need to use %4d for a 2 digit number and %5d for a one digit number. You can do that like so,

subText = [NSString stringWithFormat:@"%*d%% - %@", 6 - (int)[NSString stringWithFormat:@"%d",subpercent].length, sub percent, subfactor];

Upvotes: 0

Luca D'Alberti
Luca D'Alberti

Reputation: 4849

Why don't you use three different UILabel? I think it will be much cleaner then these 'magic' spaces! You have to imagine if you will have some other words or some other numeric values, you will still use this approach?!

Upvotes: 0

TooManyEduardos
TooManyEduardos

Reputation: 4404

How about tabs? Its dead simple.

subText = [NSString stringWithFormat:@"%3d%%\t-\t%@",subPercent,subfactor];

Upvotes: 1

Related Questions