Ios 带adjustsFontSizeToFitWidth的多行UILabel
我有一个多行UILabel,我想根据文本长度调整其字体大小。整个文本应适合标签的框架,而不会截断它 不幸的是,根据文档,只有当Ios 带adjustsFontSizeToFitWidth的多行UILabel,ios,iphone,cocoa-touch,uikit,uilabel,Ios,Iphone,Cocoa Touch,Uikit,Uilabel,我有一个多行UILabel,我想根据文本长度调整其字体大小。整个文本应适合标签的框架,而不会截断它 不幸的是,根据文档,只有当numberOfLines属性设置为1时,adjustsFontSizeToFitWidth属性“才有效” 我尝试使用 -[NSString (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode] 然后
numberOfLines
属性设置为1时,adjustsFontSizeToFitWidth
属性“才有效”
我尝试使用
-[NSString (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode]
然后减小字体大小,直到合适为止。不幸的是,此方法在内部截断文本以适应指定的大小,并返回结果截断字符串的大小。在中,0x90提供了一种解决方案,尽管有点难看,但它可以满足我的需要。具体来说,它正确地处理了单个单词与初始字体大小的宽度不匹配的情况。我稍微修改了代码,使其成为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;
}
要将其与ui标签一起使用
:
CGFloat fontSize = [label.text fontSizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:label.frame.size];
label.font = [UIFont boldSystemFontOfSize:fontSize];
编辑:修复了使用
font
初始化newFont
的代码。修复了某些情况下的崩溃。谢谢,我从其他人那里获得了更多信息,我制作了这个自定义UILabel,它将尊重最小字体大小,并且有一个额外的选项可以将文本对齐到顶部
h:
m:
我希望能有所帮助。在某些情况下,如果您知道需要多少行(例如“2”):请注意:注释中提供了一个ObjC扩展,用于计算将多行文本放入UILabel所需的字体大小。 在Swift中重写(自2016年起):
链接到完整代码:有关完整工作的解决方案,请参阅我的答案Swift 4.2的底部:
在我看来,这个问题现在有了更好的答案 我发现,当您将adjustsFontSizeToFitWidth设置为true、numberOfLines设置为0、最小缩放因子设置为足够小以允许字体根据需要收缩,以及设置默认的lineBreakMode(通过截断Tail)时,多行标签上的字体大小会自动调整
PS:我在官方文件中找不到任何关于这一变化的信息。我创建了一个问题,以了解有关此主题的更多信息我想对答案添加我自己的观点: 我认为这比其他一些答案稍有改进,因为:
.numberOfLines=0
和.lineBreakMode=.byWordWrapping
否则,最好使用标准swift库中的:.adjustFontSizeForWidth=true
这个帖子上的其他答案对我提出解决方案非常有帮助,谢谢你我发现使用
[self components separatedbycharactersinset:[NSCharacterSet whitespaceAndNewlineCharacterSet]]]
比按空格拆分更准确。这很好。我在UILabel
上添加了对最小字体大小和类别的支持,以方便感兴趣的人。这是一个很棒的方法。您可以考虑将断线模式添加为另一个参数。@ ObjjFlash,当然可能不是最好的样式。通常你会把它放在一个额外的NSString+Additions.h/.m文件中。然后你可以在任何需要的地方导入它。我尝试将其转换为iOS 7友好型,但无法得到相同的结果。iOS 7是否有类似的计量?但是,通过所有这些方法,如果您的文本在起始(现在最大)字体大小下无法放入指定的行数,constrainedToSize调用会根据您的换行符愉快地截断文本,以适应宽度。因此,你最终只能缩小以适应剩下的内容,而不是我认为你真正想要的内容,即“缩小以适应n行数的所有文本”
@interface EPCLabel : UILabel {
float originalPointSize;
CGSize originalSize;
}
@property (nonatomic, readwrite) BOOL alignTextOnTop;
@end
#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
//
// 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;
}
}
//
// String+Utility.swift
//
// Created by Philip Engberg on 29/11/2018.
// Original code from http://stackoverflow.com/a/4383281/463892 & http://stackoverflow.com/a/18951386
//
import Foundation
import UIKit
extension String {
func fontSize(with font: UIFont, constrainedTo size: CGSize, minimumScaleFactor: CGFloat) -> CGFloat {
var fontSize = font.pointSize
let minimumFontSize = fontSize * minimumScaleFactor
var attributedText = NSAttributedString(string: self, attributes: [.font: font])
var height = attributedText.boundingRect(with: CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude), options: [.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 -= 1
newFont = UIFont(name: font.fontName, size: fontSize)!
attributedText = NSAttributedString(string: self, attributes: [.font: newFont])
height = attributedText.boundingRect(with: CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin], context: nil).size.height
}
// Loop through words in string and resize to fit
for word in self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines) {
var width = word.size(withAttributes: [.font: newFont]).width
while width > size.width && width != 0 && fontSize > minimumFontSize {
fontSize -= 1
newFont = UIFont(name: font.fontName, size: fontSize)!
width = word.size(withAttributes: [.font: newFont]).width
}
}
return fontSize
}
}