Reduce UIButton label font size for third line - iphone

I have a button with changing text in it.
I want if the button text goes for third line it should reduce its font to minimumScaleFactor.
I am using this code
self.option1Button.titleLabel.minimumScaleFactor = .7;
self.option1Button.titleLabel.numberOfLines = 2;
self.option1Button.titleLabel.adjustsFontSizeToFitWidth = TRUE;
But this is not working. it doesn't change the font size when text reaches to third line.

The adjustToFit will only work for single line labels.
Try doing this:
//Create a string with the text we want to display.
self.ourText = #"This is your variable-length string. Assign it any way you want!";
/* This is where we define the ideal font that the Label wants to use.
Use the font you want to use and the largest font size you want to use. */
UIFont *font = [UIFont fontWithName:#"Marker Felt" size:28];
int i;
/* Time to calculate the needed font size.
This for loop starts at the largest font size, and decreases by two point sizes (i=i-2)
Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */
for(i = 28; i > 10; i=i-2) {
// Set the new font size.
font = [font fontWithSize:i];
// You can log the size you're trying: NSLog(#"Trying size: %u", i);
/* This step is important: We make a constraint box
using only the fixed WIDTH of the UILabel. The height will
be checked later. */
CGSize constraintSize = CGSizeMake(260.0f, MAXFLOAT);
// This step checks how tall the label would be with the desired font.
CGSize labelSize = [self.ourText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
/* Here is where you use the height requirement!
Set the value in the if statement to the height of your UILabel
If the label fits into your required height, it will break the loop
and use that font size. */
if(labelSize.height <= 180.0f)
break;
}
// You can see what size the function is using by outputting: NSLog(#"Best size is: %u", i);
// Set the UILabel's font to the newly adjusted font.
msg.font = font;
// Put the text into the UILabel outlet variable.
msg.text = self.ourText;

If you want your button to display three lines, you will have to set numberOfLines to 3. Strange but true.

Related

UILabel text to fill in the frame width

I want to build typography poster using UILabel
left and margin: 25
320(device width) - 50(sum of the margins) = 270(label width frame)
The font size of each label should change in order to fit in 270 frame width
I try with sizeToFit(),adjustsFontSizeToFitWidth=true
var margin = 0;
let label = UILabel(frame: CGRectMake(25 , 72, 270, 70));
label.backgroundColor = UIColor.clearColor();
label.textAlignment = NSTextAlignment.Left;
label.textColor = UIColor.blackColor();
label.numberOfLines = 1;
label.font = UIFont.systemFontOfSize(50.0);
label.text = "Some Text";
label.adjustsFontSizeToFitWidth = true;
self.view.addSubview(label);
margin += 60;
let label2 = UILabel(frame: CGRectMake(25 , CGFloat(72+margin), 270, 70));
label2.backgroundColor = UIColor.clearColor();
label2.textAlignment = NSTextAlignment.Left;
label2.textColor = UIColor.whiteColor();
label2.numberOfLines = 1;
label2.font = UIFont.boldSystemFontOfSize(45.0);
label2.text = "Some Text Longer";
self.view.addSubview(label2);
Screenshot when lable1 and label2 adjustsFontSizeToFitWidth=true
The text should start from the end of first grey border and end in the beginning at the start of the second grey border
adjustsFontSizeToFitWidth does not increase the size of the font in the label to fit the width.
According to Apple's documentation,
adjustsFontSizeToFitWidth is a Boolean value indicating whether the
font size should be reduced in order to fit the title string into the
label’s bounding rectangle.
Normally, the label text is drawn with the font you specify in the
font property. If this property is set to YES, however, and the text
in the text property exceeds the label’s bounding rectangle, the
receiver starts reducing the font size until the string fits or the
minimum font size is reached. In iOS 6 and earlier, this property is
effective only when the numberOfLines property is set to 1.
You can try increasing the size of the font to fit the width of the frame.
Source : https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/index.html#//apple_ref/occ/instm/UIView/sizeToFit
You can also use the following method to iteratively find the maximum size that fits the label.
How to adjust font size of label to fit the rectangle?
This should just work without changing many defaults. The posted code doesn't set adjustsFontSizeToFitWidth, look like this:
label.adjustsFontSizeToFitWidth = true

Monotouch - calculate UILabel height

I am trying to create a custom cell which consists a few UILabels.
The first label might take one or more rows, so I need to resize the label according to the number of lines (after setting the number of lines to 0, so multi-line will be enabled).
I have tried setting sizeToFit(), but it changed the alignment and width of my label.
I found this answer
but I don't know how to convert it to C#.
Can anyone point me to an example? (I already tried Googling it off-course)
This is the method from the link:
// UILabel *myLabel;
CGSize labelSize = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:UILineBreakModeWordWrap];
CGFloat labelHeight = labelSize.height;
int lines = [myLabel.text sizeWithFont:myLabel.font
constrainedToSize:myLabel.frame.size
lineBreakMode:UILineBreakModeWordWrap].height/16;
// '16' is font size
var size = myLabel.StringSize("Some really long string", myLabel.Font, myLabel.Frame.Size, UILineBreakMode.CharacterWrap);
var lines = size.Height / myLabel.Font.CapHeight;

adjusting text based on UITextView frame size

I am trying to adjust the size of the text in my UITextView so it fits. I have the following code:
NSString *storyTitle = [newsfeedToSubject.properties valueForKey:#"title"];
int currentFontSize = 18;
UIFont *currentFont = [UIFont fontWithName:kProximaNovaBold size:currentFontSize];
CGSize storyTitleSize = [storyTitle sizeWithFont:currentFont constrainedToSize:self.newsfeedStoryTitle_.frameSize lineBreakMode:UILineBreakModeWordWrap];
while (storyTitleSize.height >= self.newsfeedStoryTitle_.frameHeight){
currentFontSize--;
currentFont = [UIFont fontWithName:kProximaNovaBold size:currentFontSize];
storyTitleSize = [storyTitle sizeWithFont:currentFont constrainedToSize:self.newsfeedStoryTitle_.frameSize lineBreakMode:UILineBreakModeWordWrap];
}
[self.newsfeedStoryTitle_ setFont:currentFont];
[self.newsfeedStoryTitle_ setText:storyTitle];
[self.newsfeedStoryTitle_ setBackgroundColor:[UIColor redColor]];
However, here's what I am getting:
I tried with different line break mode and also set the autoresize to none, but it didn't help. Any idea?
Your while loop will not do what you want because you are using
storyTitleSize.height
to determine the size of the frame, which will not take into account the wrap around effect of the text. One suggestion would be to truncate the string and only display a certain amount of characters of the title. Otherwise, you will need to calculate how many line breaks you will have, based on the width of the frame and the length of the string, and use
while(storyTitleSize.height * numLineBreaks >= self.newsFeedStoryTitle_.frameHeight)
{
...
}
Hope that helps.
You can also dynamically resize your frame (UITextView) as in this thread
try these code
while (self.textView.contentSize.height >= frameHeight){
currentFontSize--;
currentFont = [UIFont fontWithName:kProximaNovaBold size:currentFontSize];
[self.textView setFont:currentFont];
self.textView.text = #"your string";
}

How to get the size of a NSString

A "quicky": how can I get the size (width) of a NSString?
I'm trying to see if the string width of a string to see if it is bigger than a given width of screen, case in which I have to "crop" it and append it with "...", getting the usual behavior of a UILabel. string.length won't do the trick since AAAAAAAA and iiiiii have the same length but different sizes (for example).
I'm kind of stuck.
Thanks a lot.
This is a different approach. Find out the minimum size of the text so that it won't wrap to more than one line. If it wraps to over one line, you can find out using the height.
You can use this code:
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *myString = #"This is a long string which wraps";
UIFont *myFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize myStringSize = [myString sizeWithFont:myFont
constrainedToSize:maximumSize
lineBreakMode:self.myLabel.lineBreakMode];
300 is the width of the screen with a little space for margins. You should substitute your own values for font and size, and for the lineBreakMode if you're not using IB.
Now myStringSize will contain a height which you can check against the height of something you know is only 1 line high (using the same font and size). If it's bigger, you'll need to cut the text. Note that you should add a ... to the string before you check it again (adding the ... might push it over the limit again).
Put this code in a loop to cut the text, then check again for the correct height.
Use below method.
Objective-C
- (CGSize)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font {
CGSize size = CGSizeZero;
if (text) {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height + 1);
}
return size;
}
Swift 3.0
func findHeight(forText text: String, havingWidth widthValue: CGFloat, andFont font: UIFont) -> CGSize {
var size = CGSizeZero
if text {
var frame = text.boundingRect(withSize: CGSize(width: widthValue, height: CGFLOAT_MAX), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
size = CGSize(width: frame.size.width, height: frame.size.height + 1)
}
return size
}
You need to use Core Graphics to measure the string, as rendered in your specified font and size. See the answers to Measuring the pixel width of a string for a walkthrough.
sizeWithFont:constrainedToSize:lineBreakMode
is deprecated now. Use below code snippet,
UIFont *font=[UIFont fontWithName:#"Arial" size:16.f];
NSString *name = #"APPLE";
CGSize size = [name sizeWithAttributes:#{NSFontAttributeName:font}];
For whatever its worth --- I think the OP takes the wrong way to get there... if the measurement of width only serves to find the place where text should be clipped, and followed by ellipsis --- then OP should be aware of that this facility is implemented in all Text Views in Cocoa...
Pay attention to this enumeration:
typedef NS_ENUM(NSUInteger, NSLineBreakMode) {
NSLineBreakByWordWrapping = 0, // Wrap at word boundaries, default
NSLineBreakByCharWrapping, // Wrap at character boundaries
NSLineBreakByClipping, // Simply clip
NSLineBreakByTruncatingHead, // Truncate at head of line: "...wxyz"
NSLineBreakByTruncatingTail, // Truncate at tail of line: "abcd..."
NSLineBreakByTruncatingMiddle // Truncate middle of line: "ab...yz"
} API_AVAILABLE(macos(10.0), ios(6.0), watchos(2.0), tvos(9.0));
By setting the line breaking mode of your text-field or text view to NSLineBreakByTruncatingTail, you'll achieve what you want, and probably at higher quality, without implementing yourself.

Font size in pixels

On an iPhone how do I calculate the size of a character in pixels for a given point size?
Point sizes are defined as 1/72 of an inch. That is, a 72-point font is approximately 1 inch from the lowest descent to the highest ascent. So the maximum height of a glyph in a 72pt font is about 1 inch.
Apple's iphone tech specs page claims that the iPhone currently has a resolution of 163 pixels per inch. So 72 points is 163 pixels, or about 2.2639 pixels per point. Just remember that every glyph varies in height and width, so this is a very rough estimate of size. Generally, the distance between baselines will be a bit larger than the font's point size so that lines of text don't crash into each other.
If you need exact measurements (and you probably do) then you'll need to actually measure the font glyphs using the font metric information. You can do this by using NSString's UIKit additions, which will let you measure the size of a particular string when rendered on screen.
To match font sizes (in Points) on the iPhone4 with font sizes (in Points) in Photoshop you have to set your Photoshop document to 144dpi. I have run a number of tests and that's the resolution that produces 1:1 results.
Steps:
Take a screenshot of “Settings » General » Accessibility » Large Text” on an iPhone4
Open the screenshot in Photoshop
Change the resolution from 72dpi to 144dpi with “Resample Image” off
Retype the text in Photoshop (in Points) to match size in the screenshot
I have gone through a number of different resolutions, including the 163dpi that was mentioned in the answer above, and I found that 144dpi produces 1:1 results. I have also tested this against a native app where I know the point sizes and the 144dpi was match there too.
Our graphic artist was very specific on certain devices to use pixel sizes instead of point size.
The function below will return a font based on pixel size.
It uses a brute force method to find the closet font, but then caches the results so next time the return will be very fast. I always appreciate comments on how this code could be made better. I use this function as a static class member in class called utils.
You can easily paste into any class you are using.
Hope it is of some help.
/** return a font as close to a pixel size as possible
example:
UIFont *font = [Utils fontWithName:#"HelveticaNeue-Medium" sizeInPixels:33];
#param fontName name of font same as UIFont fontWithName
#param sizeInPixels size in pixels for font
*/
+(UIFont *) fontWithName:(NSString *) fontName sizeInPixels:(CGFloat) pixels {
static NSMutableDictionary *fontDict; // to hold the font dictionary
if ( fontName == nil ) {
// we default to #"HelveticaNeue-Medium" for our default font
fontName = #"HelveticaNeue-Medium";
}
if ( fontDict == nil ) {
fontDict = [ #{} mutableCopy ];
}
// create a key string to see if font has already been created
//
NSString *strFontHash = [NSString stringWithFormat:#"%#-%f", fontName , pixels];
UIFont *fnt = fontDict[strFontHash];
if ( fnt != nil ) {
return fnt; // we have already created this font
}
// lets play around and create a font that falls near the point size needed
CGFloat pointStart = pixels/4;
CGFloat lastHeight = -1;
UIFont * lastFont = [UIFont fontWithName:fontName size:.5];\
NSMutableDictionary * dictAttrs = [ #{ } mutableCopy ];
NSString *fontCompareString = #"Mgj^";
for ( CGFloat pnt = pointStart ; pnt < 1000 ; pnt += .5 ) {
UIFont *font = [UIFont fontWithName:fontName size:pnt];
if ( font == nil ) {
NSLog(#"Unable to create font %#" , fontName );
NSAssert(font == nil, #"font name not found in fontWithName:sizeInPixels" ); // correct the font being past in
}
dictAttrs[NSFontAttributeName] = font;
CGSize cs = [fontCompareString sizeWithAttributes:dictAttrs];
CGFloat fheight = cs.height;
if ( fheight == pixels ) {
// that will be rare but we found it
fontDict[strFontHash] = font;
return font;
}
if ( fheight > pixels ) {
if ( lastFont == nil ) {
fontDict[strFontHash] = font;
return font;
}
// check which one is closer last height or this one
// and return the user
CGFloat fc1 = fabs( fheight - pixels );
CGFloat fc2 = fabs( lastHeight - pixels );
// return the smallest differential
if ( fc1 < fc2 ) {
fontDict[strFontHash] = font;
return font;
} else {
fontDict[strFontHash] = lastFont;
return lastFont;
}
}
lastFont = font;
lastHeight = fheight;
}
NSAssert( false, #"Hopefully should never get here");
return nil;
}
I believe you're looking for the UIFont NSString extensions that allow you to calculate the size of a string given a UIFont.
Here is the Link
Specifically the sizeWithFont methods.
You can't reliably convert points to pixels as the ppi (points-per-inch) will change from monitor to monitor. Have a read;
http://hsivonen.iki.fi/units/
Convert Pixels to Points
That said, some people have put together a few reference tables and calculators that may get you started;
http://www.unitconversion.org/typography/postscript-points-to-pixels-x-conversion.html
http://sureshjain.wordpress.com/2007/07/06/53/
The easiest way to get the pixel height for a given font and size is to use the boundingRect method on NSString. (I'm using #"Ap" here to make sure it contains a descender and an ascender.)
- (CGFloat)heightForFont:(UIFont *)font
{
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGRect boundingRect = [#"Ap" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:#{NSFontAttributeName:font} context:context];
return boundingRect.size.height;
}
I will add them as I figure them out:
A sizedToFit UILabel with a 12pt systemFont is 15px high.
You can calculate the pixel size on the fly by rendering a NSAttributedString and getting its size.
extension UIFont {
var pixelSize: CGFloat {
let string = "AWZgjpq"
let attributedString = NSMutableAttributedString(string: string)
attributedString.setAttributes([.font: self], range: NSRange(location: 0, length: string.count))
return attributedString.size().height
}
}
Further optimizations could be to add a lookup dictionary and cache results and/or make the test string not a variable (but the call itself is really fast). Also, if your font has some very irregular glyphs you can add them to the test string as well.
Usage: let pixelSize = label.font.pixelSize