多行UILabel与adjustsFontSizeToFitWidth

我有一个多行UILabel的字体大小,我想调整取决于文本的长度。 整个文本应该适合标签的框架而不截断它。

不幸的是,根据文档adjustsFontSizeToFitWidth属性“仅在numberOfLines属性设置为1时才有效”。

我试图确定使用调整的字体大小

 -[NSString (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode] 

然后递减字体大小直到适合。 不幸的是,这个方法在内部截断了文本以适合指定的大小,并返回所得截断string的大小。

在这个问题中 ,0x90提供了一个解决scheme,虽然有点难看,但是却是我想要的。 具体而言,它正确地处理了单个单词不适合初始字体大小的情况。 我已经稍微修改了代码,以便它在NSString上作为一个类别:

 - (CGFloat)fontSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size { CGFloat fontSize = [font pointSize]; CGFloat height = [self sizeWithFont:font constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height; UIFont *newFont = font; //Reduce font size while too large, break if no height (empty string) while (height > size.height && height != 0) { fontSize--; newFont = [UIFont fontWithName:font.fontName size:fontSize]; height = [self sizeWithFont:newFont constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height; }; // Loop through words in string and resize to fit for (NSString *word in [self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) { CGFloat width = [word sizeWithFont:newFont].width; while (width > size.width && width != 0) { fontSize--; newFont = [UIFont fontWithName:font.fontName size:fontSize]; width = [word sizeWithFont:newFont].width; } } return fontSize; } 

要使用它与UILabel

  CGFloat fontSize = [label.text fontSizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:label.frame.size]; label.font = [UIFont boldSystemFontOfSize:fontSize]; 

编辑 :修复了用font初始化newFont的代码。 修复某些情况下的崩溃。

本博客文章中提供的代码也解决了这个问题。 不过,我发现,如果你需要一次计算多个标签的字体大小,那么循环遍历所有可能的字体大小有点太慢了,所以我修改了一下代码,现在运行得更快了。

就我所知,唯一的问题就是,它没有考虑到Ortwin指出的单个单词不适合初始字体大小的情况。

所以,如果你正在寻找一个更快的解决scheme,试试这个。 (作为UIFont的一个类别)

 + (UIFont*)fontWithName:(NSString *)fontName minSize:(CGFloat)minSize maxSize:(CGFloat)maxSize constrainedToSize:(CGSize)labelSize forText:(NSString*)text { UIFont* font = [UIFont fontWithName:fontName size:maxSize]; CGSize constraintSize = CGSizeMake(labelSize.width, MAXFLOAT); NSRange range = NSMakeRange(minSize, maxSize); int fontSize = 0; for (NSInteger i = maxSize; i > minSize; i--) { fontSize = ceil(((float)range.length + (float)range.location) / 2.0); font = [font fontWithSize:fontSize]; CGSize size = [text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; if (size.height <= labelSize.height) range.location = fontSize; else range.length = fontSize - 1; if (range.length == range.location) { font = [font fontWithSize:range.location]; break; } } return font; } 

在某些情况下,如果您知道需要多less行数(例如“2”),则可以将“换行”从“字换行”更改为“截断尾行”:Credit: Becky Hansmeyer

谢谢,与其他人一样,我做了这个自定义的UILabel,这将尊重最小的字体大小,并有一个奖励选项,以文本顶部。

H:

 @interface EPCLabel : UILabel { float originalPointSize; CGSize originalSize; } @property (nonatomic, readwrite) BOOL alignTextOnTop; @end 

L:

 #import "EPCLabel.h" @implementation EPCLabel @synthesize alignTextOnTop; -(void)verticalAlignTop { CGSize maximumSize = originalSize; NSString *dateString = self.text; UIFont *dateFont = self.font; CGSize dateStringSize = [dateString sizeWithFont:dateFont constrainedToSize:CGSizeMake(self.frame.size.width, maximumSize.height) lineBreakMode:self.lineBreakMode]; CGRect dateFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, dateStringSize.height); self.frame = dateFrame; } - (CGFloat)fontSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size { CGFloat fontSize = [font pointSize]; CGFloat height = [self.text sizeWithFont:font constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height; UIFont *newFont = font; //Reduce font size while too large, break if no height (empty string) while (height > size.height && height != 0 && fontSize > self.minimumFontSize) { fontSize--; newFont = [UIFont fontWithName:font.fontName size:fontSize]; height = [self.text sizeWithFont:newFont constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height; }; // Loop through words in string and resize to fit if (fontSize > self.minimumFontSize) { for (NSString *word in [self.text componentsSeparatedByString:@" "]) { CGFloat width = [word sizeWithFont:newFont].width; while (width > size.width && width != 0 && fontSize > self.minimumFontSize) { fontSize--; newFont = [UIFont fontWithName:font.fontName size:fontSize]; width = [word sizeWithFont:newFont].width; } } } return fontSize; } -(void)setText:(NSString *)text { [super setText:text]; if (originalSize.height == 0) { originalPointSize = self.font.pointSize; originalSize = self.frame.size; } if (self.adjustsFontSizeToFitWidth && self.numberOfLines > 1) { UIFont *origFont = [UIFont fontWithName:self.font.fontName size:originalPointSize]; self.font = [UIFont fontWithName:origFont.fontName size:[self fontSizeWithFont:origFont constrainedToSize:originalSize]]; } if (self.alignTextOnTop) [self verticalAlignTop]; } -(void)setAlignTextOnTop:(BOOL)flag { alignTextOnTop = YES; if (alignTextOnTop && self.text != nil) [self verticalAlignTop]; } @end 

我希望它有帮助。

注释中提供了一个ObjC扩展,用于计算将多行文本合并到UILabel所需的字体大小。 它在Swift中被重写(因为它是2016年):

 // // NSString+KBAdditions.swift // // Created by Alexander Mayatsky on 16/03/16. // // Original code from http://stackoverflow.com/a/4383281/463892 & http://stackoverflow.com/a/18951386 // import Foundation import UIKit protocol NSStringKBAdditions { func fontSizeWithFont(font: UIFont, constrainedToSize size: CGSize, minimumScaleFactor: CGFloat) -> CGFloat } extension NSString : NSStringKBAdditions { func fontSizeWithFont(font: UIFont, constrainedToSize size: CGSize, minimumScaleFactor: CGFloat) -> CGFloat { var fontSize = font.pointSize let minimumFontSize = fontSize * minimumScaleFactor var attributedText = NSAttributedString(string: self as String, attributes:[NSFontAttributeName: font]) var height = attributedText.boundingRectWithSize(CGSize(width: size.width, height: CGFloat.max), options:NSStringDrawingOptions.UsesLineFragmentOrigin, context:nil).size.height var newFont = font //Reduce font size while too large, break if no height (empty string) while (height > size.height && height != 0 && fontSize > minimumFontSize) { fontSize--; newFont = UIFont(name: font.fontName, size: fontSize)! attributedText = NSAttributedString(string: self as String, attributes:[NSFontAttributeName: newFont]) height = attributedText.boundingRectWithSize(CGSize(width: size.width, height: CGFloat.max), options:NSStringDrawingOptions.UsesLineFragmentOrigin, context:nil).size.height } // Loop through words in string and resize to fit for word in self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) { var width = word.sizeWithAttributes([NSFontAttributeName:newFont]).width while (width > size.width && width != 0 && fontSize > minimumFontSize) { fontSize-- newFont = UIFont(name: font.fontName, size: fontSize)! width = word.sizeWithAttributes([NSFontAttributeName:newFont]).width } } return fontSize; } } 

链接到完整的代码: https : //gist.github.com/amayatsky/e6125a2288cc2e4f1bbf