iphone - calculating the font size - iphone

I have to show a label with font size = 14
when the view is 480x320.
Supposing I would like to do this in a way that my code will be working well for all future device's screen sizes, including iPad and others following (I am sure more will come), what is the best way to do that?
I could do this proportionally, I mean, if the scale increased X, increase the fonts X, but my concern is the different aspect ratios of the devices.
The iPhone aspect ratio is 1.5, but iPad's is 1.33, and other aspect ratios can come... I am not sure if this simple scale method will be enough to produce font consistency across all devices.
Any suggestions?
thanks for any help.

Simply setting uiLabel.adjustsFontSizeToFitWidth = YES will cause your text to scale down to fit the text field. Just make sure your font size is large enough for the iPad to begin with, because the text will never be scaled up.
Of course, you also need to make sure the UILabel itself is resized along with its superview, or neither the UILabel nor its contents will be scaled. You can do that using the Size tab in Interface Builder, or programatically using the UILabel's autoresizingMask property.

You could try to use this code. It will automatically scale your text down to fit within a certain width (here the contentRect). Just specify the minimum and maximum acceptable font size to use:
#define MAX_FONT_SIZE
#define MIN_FONT_SIZE
#define LEFT_TEXT_OFFSET
#define TEXT_TOP
UIFont *theFont = [UIFont systemFontOfSize: MAX_FONT_SIZE];
CGRect contentRect = self.bounds;
CGFloat boundsX = contentRect.origin.x;
CGPoint point;
CGSize width = contentRect.size.width;
point = CGPointMake(boundsX + LEFT_TEXT_OFFSET, TEXT_TOP);
[theText drawAtPoint:point forWidth:width withFont:theFont
minFontSize:MIN_FONT_SIZE actualFontSize:NULL
lineBreakMode:UILineBreakModeTailTruncate
baselineAdjustment:UIBaselineAdjustmentAlignBaselines];
Claus

Related

iPhone: UILabel text does not fit the way i want

I have a UILabel with some text on it, what I want is if the text with the given font does not fit to the label, I want it to be first linebreaked to a second line, and if still does not fit then it should automatically adjust those 2 lines to a smaller font.
I experienced with the IB changing the settings of linebreaks and number of rows, but couldn't get what I want.
Any recommendadtions?
To my knowledge UILabel does not support auto adjusting the font when there is more than one line.
The only way I know of it to iteratively calculate a fitting font size and then to set the appropriate font manually.
Maybe the sizeWithFont: method is a solution for you:
– sizeWithFont:forWidth:lineBreakMode:
This calculates the width / height of a NSString with the appropriate font / settings

How to use NSString's sizeWithFont and drawInRect to workout how much of a string to draw

I'm drawing multiple 'pages' of imagery using a CGContext in the iOS. I've used sizeWithFont and drawInRect combinations extensively in my app. What I need to do is split a large chunk of text across multiple pages. I can size it and work out whether or not it needs another page but how do I know where to chop it? Do I have to do an ugly loop to check word by word until I find a string length that perfectly fits the page and then chop the string at that point? Is there a smarter way?
Any ideas?
Thanks.
The NSString additions to UIKit for drawing text, you can pre-determine the exact amount of space required to render a given text for a given font. If splitting the text into pages, you could use this method.
– sizeWithFont:constrainedToSize:lineBreakMode:
Assuming the font and line break mode is known, create a CGSize having the same width as your page, and use a sufficiently number for height. This would be the maximum size that we are constraining the text into.
CGSize maximumSize = CGSizeMake(pageWidth, 999999999);
CGSize expectedSize = [veryLongString sizeWithFont:theFont constrainedToSize:maximumSize lineBreakMode:theLineBreakMode];
expectedSize will tell us the size that the text will take assuming if it could extend vertically infinitely (well close to). To find the number of pages required, just divide the total height by the height of one page.
NSInteger totalPages = ceil(expectedSize.height / heightOfOnePage);
You would also want to adjust the height of one page to make sure that the last line of text doesn't get clipped. For that to happen, the height of the page should be a multiple of the font's line height. Say the initial page height is 300px, and the font-height is 16px, then there will be some clipping as 300/16 = 18.75 which is not a whole number.
NSInteger linesWithoutClipping = floor(initialPageHeight / theFont.lineHeight);
CGFloat optimalPageHeight = linesWithoutClipping * theFont.lineHeight;
Taking the floor value 18 and multiplying with the font line height 16, we get an optimal page height of 288 to ensure there's no clipping.
Note that lineHeight was introduced in iOS 4.0, but you could calculate it yourselves if needed for older versions.
The way I get around this problem is to split by line returns.
NSArray * paragraphs = [text componentsSeparatedByString:#"\n"];
You still have to do all the work to determine page breaks and alike but I have found this the best workaround so far.

iPhone - UIView orientation changes

I got a subclass of UIView in which I draw an NSString object using the drawInRect:withFont:lineBreakMode:alignment: method.
Unfortunately, when I change the orientation of the device, say from portrait into landscape mode, the text doesn't get redrawn correctly but gets scaled and distorted against my intentions.
How can I solve this problem?
This is part of how Core Animation animates transitions. A snapshot of your view is taken, and then stretched/moved into the new location.
There are a number of ways you can tackle this. First of all you can try this:
self.contentMode = UIViewContentModeRedraw;
This might be all you need and will tell Core Animation to redraw your contents instead of using a snapshot. If you still have issues, you can try defining a "stretchable" region that is stretched instead of your text.
For example, if you know you have a vertical slice of your view where there is never any text, you can define the content stretch to be in that little section and any stretching only occurs there, hopefully keeping your text intact.
CGFloat stretchStartX = 25.0f;
CGFloat stretchEndX = 30.0f;
/* Content stretch values are from 0.0-1.0, as a percentage of the view bounds */
self.contentStretch = CGRectMake(stretchStartX / self.bounds.size.width,
0.0f,
stretchEndX / self.bounds.size.width,
1.0f);
This causes the your view to be stretched only between x values 25 and 30.

How to fit a String into a rectangle?

I have an NSString and want to fit it into a rectangle. The rectangle has a specified size, lets say width=150 and height=30. When the String is short and has only one character, it can be as high as the rectangle. More specific: It can have a big font size. But if the string has too much characters and would exceed the bounds of the rectangle, it must become smaller. More specific: It's font size must become smaller, so that it won't exceed the bounds of the rectangle. Is there a way of doing that without messing around in core graphics?
For some reason, UILabel's adjustsFontSizeToFitWidth Property has no effect. The text keeps beeing small even if there is plently of space.
I've set that to
label.adjustsFontSizeToFitWidth = YES;
but nothing happens. I hope there is another way to do that...
There are several part to UILabel that make this possible, but first you have to know if you want to truncate the string or make the font size smaller to fit in the rectangle.
For both cases you'll want to set the UILabel's numberOfLines property to 0, allowing the label to wrap as much as necessary. Then you'll want to set the frame of the UILabel to match the rectangle you're looking to fit. From there you take one of two paths:
Truncation: Set the lineBreakMode property to UILineBreakModeClip, UILineBreakModeHeadTruncation, UILineBreakModeTailTruncation, or UILineBreakModeMiddleTruncation depending on the truncation behavior you're looking for.
Resizing: Set the lineBreakMode to either UILineBreakModeWordWrap or `UILineBreakModeCharacterWrap' depending on your preference. Then you'll need to enter a loop to figure out the right font size. Start with a reasonable font size (e.g., 12) and:
Set the font property of the UILabel with a UIFont that matches that size
Call - (void) sizeToFit for the UILabel.
Check the frame for the UILabel:
If the frame will fit within the bounds you need it to, you're done
If the frame is still to big, drop the size of the font and repeat the loop
For the latter option you'll want to make sure you're not squeezing the text into oblivion, so you'll want to put a minimum size cap on the font size.
You can get more information from the UILabel and UIFont documentation.
adjustsFontSizeToFitWidth adjusts the font size down, not up.
Set the font on your UILabel to an appropriately large size, and UILabel will shrink it when necessary to fit in its bounds.
Set label font size to desired normal size.
Set label minimum font size to
smallest possible font
(minimumFontSize property)
Set adjustsFontSizeToFitWidth to
YES.
If you need multiple lines, set lineCount to 0 as the other poster noted.

drawAtPoint: and drawInRect: blurry text

When drawing strings using drawAtPoint:, drawInRect: and even setting the text property of UILabels - the text can sometimes appear slightly blurry.
I tend to use Helvetica in most places, and I notice that specific font sizes cause some level of blurriness to occur, both in the simulator and on the device.
For example:
UIFont *labelFont = [UIFont fontWithName:#"Helvetica-Bold" size:12];
Will cause the resulting label to have slightly blurry text.
UIFont *labelFont = [UIFont fontWithName:#"Helvetica-Bold" size:13];
Results in crisp text.
My question is why does this occur? And is it just a matter of selecting an optimal font size for a typeface? If so, what are the optimal font sizes?
UPDATE: It seems that perhaps it is not the font size that is causing the blurriness. It may be that the center of the rect is a fractional point. Here is a comment I found on the Apple dev forums:
Check the position. It's likely on a
fractional pixel. Change center to be
integer value.
I rounded off the values of all my points, but there are still places where text remains blurry. Has anyone come across this issue before?
I have resolved this.
Just make sure that the point or rect in which you are drawing does not occur on a fractional pixel.
I.e. NSLog(#"%#", NSStringFromCGRect(theRect)) to determine which point is being drawn on a fractional pixel. Then call round() on that point.
You might want to look at NSIntegralRect(), it does what you want.
Pardon my ignorance if this is incorrect, I know nothing about iPhone or Cocoa.
If you're asking for the text to be centered in the rect, you might also need to make sure the width and/or height of the rect is an even number.
I have had this problem too, but my solution is different and may help someone.
My problem was text blur after changing the size of a UIView object thru TouchesBegan
and CGAffineTransformMakeScale, then back to CGAffineTransformIdentity in TouchesEnded.
I tried both the varying text size and rounding of x and y center points but neither worked.
The solution for my problem was to use even sizes for the width and height of my UIView !!
Hope this helps ....
From my experiments, some fonts don't render clearly at certain sizes. e.g. Helvetica-Bold doesn't render "." well at 16.0f, but they're clear at 18.0f. (If you look closely, the top pixel of the "." is blurry.)
After I noticed that, I've been irked every time I see that UIView, since it's rendered dynamically.
In my case, I drew text on a custom CALayer and turned out to be pretty blurry. I solved it by setting contentScale with appropriate value:
Objective-C:
layer.contentsScale = [UIScreen mainScreen].scale;
Swift:
layer.contentsScale = UIScreen.main.scale