I’m trying to measure a string to be drawn. I have tried sizeWithAttributes:, but that doesn’t make a difference between different characters:
NSLog(#"A: %#", NSStringFromCGSize([#"." sizeWithAttributes:labelAttributes]));
NSLog(#"B: %#", NSStringFromCGSize([#"X" sizeWithAttributes:labelAttributes]));
A: {6, 23}
B: {12, 23}
Note that the reported height is the same for both characters. Is there a call that would honour the height difference between . and X?
There's no such thing as "real height". Font metrics are a complex topic.
A string (consisting of characters) is converted to a bunch of glyphs. Those glyphs define what will be visible (rendered). This process involves endless subtleties that might change what you define as the "real height".
Examples:
Some characters extend very far over the normal line height.
Some (graphical) rendering options stretch out beyond the bounding box of all glyphs (like shadows or outlines).
Font metrics contain a myriad of different values for what could be considered the bounding box of a character (or glyph).
This image shows the string "abc f 123" rendered using the font Zapfino (in TextEdit.app on a Mac). The f character is selected (green box). The visual character stretches far beyond of what the selection considers the bounding box.
The red text has a shadow applied to it. It's not easy to calculate the bounding box of this part of the text either.
Your case sounds like you consider a "." character to have a smaller size than a "X". But has a space character a zero size then? It's really difficult to define the "real size" without exact knowledge of the use case. And even then there are often many undefined edge cases.
I had a use case where I wanted to convert strings to PNG images (stupid, I know). In that case the best option was to render the string into a large bitmap context and then search through the raw data bitplanes from the outside inwards until finding first non-transparent pixels.
Agree with Nikolai. I think the best you can do is to get smallest possible size like following.
self.myLabel.text = #".";
[self.myLabel setNeedsLayout];
[self.myLabel layoutIfNeeded];
NSLog(#"A: %#", NSStringFromCGSize([self.myLabel systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]));
self.myLabel.text = #"X";
[self.myLabel setNeedsLayout];
[self.myLabel layoutIfNeeded];
NSLog(#"B: %#", NSStringFromCGSize([self.myLabel systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]));
A: {5, 21}
B: {11, 21}
If you want the smallest possible size, pass UILayoutFittingCompressedSize; for the largest possible size, pass UILayoutFittingExpandedSize.
Related
I have a UILabel with a font of size 50 and text 1. At runtime, its text is changed to other numbers.
If I, say, center it in its superview, the automatically detected (intrinsic content size) height is a lot bigger than the actual text, and this is because it tries not to crop other lower characters like g.
The thing is that I know I won't use other characters than digits. I also don't want to set a fixed height constraint for it.
UIFont metrics include ascender, descender, cap height, x height, etc... all of which determines how the characters fit into a container. There is a good explanation and diagram here: http://cocoanetics.com/2010/02/understanding-uifont
If you really want to get the height (and/or width) of the individual character "glyphs" you'll need to use Core Text. This will include calling CTFontGetGlyphsForCharacters() and CTFontCreatePathForGlyph() to get the "glyph path" (a CGPath object), at which point you can get the "bounding box" to determine the exact size.
Lots of discussions and example code out there... A good starting point is simply searching for CTFontCreatePathForGlyph
I have a UILabel that is configured with dynamic parameters:
textLabel.font = UIFont.systemFontOfSize(some_dynamic_size, weight: some_dynamic_font_weight)
textLabel.numberofLines = some_dynamic_number_lines
textLabel.frame = CGRectMake(0, 0, dynamic_width, dynamic_height)
How to calculate the number of characters this UILabel can hold before it gets truncated?
Calculate how tall the label would want to be given its font, text, and width. If that is taller than you want to make it, the text won't all fit.
The issue is that your label will be able to fit more or less text given on the font that you use and the size that it is set too. If you set that to a standard size say for instance San Francisco at 12pt then you will still have a varying amount of letters that can fit because not all letters are the same width for instance 'WWW' is allot bigger than ' lll ' but you could determine a "best estimate" by taking the average letter width. Then dividing the size of the label by that then you would have a general idea of how many letters could fit but you also need to account for the '...' that is inserted.
But I would suggest not concatenating at all and just make the text a variable size so it can shrink and show the whole word. I suggest looking into 'dynamic text' but I don't know what your application is so that may not be the best suggestion. Hope that helps 😜
I have a font where unfortunately the numbers and letters are different heights. I need to display a reference code which is a mix of letters and numbers and the uneven heights of the characters looks jarring. Is it possible with core text (or another technology on iOS) to render certain characters with a slightly stretched height so that it looks even numbers and letters are displayed together.
E.g i have the string '23Rt59RQ' I need the 2,3,5,9 to be rendered with a larger height.
AFAICT, there's nothing in the CGContext API (which is what you'd want to use for laying out sets of glyphs) which would directly, easily facilitate this.
If it's really very important to use the font you are using, you could make separate calls to CGContextShowGlyphsAtPositions for alphabetic and numeral characters, calling CGContextSetFontSize each time so that the end result ends up matching, but this is a lot of overhead for just drawing text, and will probably result in undesirable performance.
My real advice would be to pick a better font so that this isn't even an issue :)
In the end of used regex to identify the character groups and then created an attributed string varying the font size in the font given in the NSFontAttributeName attribute according to which characters were to be displayed.
Kinda hacky but it had the desired effect.
In an iOS app I need to use a specific font but each character needs to be taller, thinner, and the spacing closed up to fit correctly. Is it possible to stretch/squish a font programmatically?
When you're adding text to a PDF file there are multiple ways to influence how the text is going to appear. The most generic way (and the way that might actually be sufficient for you) is to scale the text matrix:
void CGContextSetTextMatrix ( CGContextRef c, CGAffineTransform t );
As mentioned in the comment by #mkl, you can provide a matrix that will scale up in the Y direction while scaling down in the X direction. The effect will be that the letters are stretched out vertically and squished horizontally.
Normally I would expect you don't have to touch the spacing in that case, as spacing will be "squished" together just as the other characters.
Just in case that isn't sufficient, PDF actually does provide a way to change the spacing between characters too:
void CGContextSetCharacterSpacing ( CGContextRef context, CGFloat spacing );
While Apple's description talks about "additional space" to add between characters, the PDF specification and I suspect Apple's implementation as a result allows the spacing value to be both positive and negative. A negative value would have the effect of moving the characters closer together.
Seems like the best option would be to create your own custom font.
You are able to change the kerning of your font (the space between the letters) and the thickness/thinness of the font, however you probably aren't able to edit the height of the font, unless you edit the bounding box the font is inside of to scale the letters differently.
You might also want to consider using a different font...or if you're REALLY hardcore you can edit the font yourself using photoshop/illustrator.
I have an NSAttributedString which I draw into a rectangle (no text views here.) I allow the user to resize that rectangle thus forcing the text to wrap onto multiple lines. All is good and I'm using NSTextContainer etc to figure out the text bounding height for a given width.
The challenge I have is knowing what the MINIMUM width can be - so that I don't allow the user to resize the rectangle to be narrower than the widest character/glyph in the string.
I have a working solution which involves getting the bounding rect for each glyph (boundingRectForGlyphRange) and keeping track of the largest - but this is a real performance killer on larger strings.
Anyone know of a better way?
Thanks
When you choose your font and display language, you could compile a lookup of all possible glyph widths. Order it descending with the largest glyphs first, then use rangeOfString: != NSNotFound; breaking after you find one (this is your maximum glyph width).
Hard to say what the performance difference is like, but it is probably faster than fetching the width of all your glyphs every time since it's just a string comparison instead of a font measurement.