动态更改UILabel字体大小

213

我目前有一个 UILabel

factLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 280, 100)];
factLabel.text = @"some text some text some text some text";
factLabel.backgroundColor = [UIColor clearColor];
factLabel.lineBreakMode = UILineBreakModeWordWrap;
factLabel.numberOfLines = 10;
[self.view addSubview:factLabel];

在我的iOS应用的整个生命周期中,factLabel 会获取许多不同的值。有些是有多个句子的,有些只有5或6个单词。

我该如何设置 UILabel 来使字体大小随着文本内容的变化而自动调整,以便始终适合我定义的范围?


2
对于2016年,我真的相信唯一“好”的解决方案是使用“使用自动收缩”方法。使UILabel框实际大小,使字体填充UILabel,选择自动收缩,设置一个标题巨大的字体大小(300),并确保在最小/最大模拟器上进行测试。(因此,目前为止是4s / PadPro。)完整的解释:https://dev59.com/X1sW5IYBdhLWcg3wSVqM#35154493 这是今天唯一真正的解决方案。 - Fattie
12个回答

407

单行代码:

factLabel.numberOfLines = 1;
factLabel.minimumFontSize = 8;
factLabel.adjustsFontSizeToFitWidth = YES;

上述代码将调整文本的字体大小,使其适应标签内的空间,例如将字体大小调整到8numberOfLines = 1是必需的。

多行文本:

对于numberOfLines > 1,可以通过NSString的sizeWithFont:... UIKit addition方法来确定最终文本的大小,例如:

CGSize lLabelSize = [yourText sizeWithFont:factLabel.font
                                  forWidth:factLabel.frame.size.width
                             lineBreakMode:factLabel.lineBreakMode];

之后,您可以使用生成的lLabelSize来调整标签的大小,例如(假设您只更改标签的高度):

factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, factLabel.frame.size.width, lLabelSize.height);

iOS6

单行:

iOS 6 开始,minimumFontSize已被弃用。这一行

factLabel.minimumFontSize = 8.;

可以改变为:

factLabel.minimumScaleFactor = 8./factLabel.font.pointSize;

iOS7

多行情况:

从iOS7开始,sizeWithFont被废弃了。 多行情况可以使用以下方法:

factLabel.numberOfLines = 0;
factLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(factLabel.frame.size.width, CGFLOAT_MAX);
CGSize expectSize = [factLabel sizeThatFits:maximumLabelSize];
factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, expectSize.width, expectSize.height);

iOS 13(Swift 5):

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5

但我不想改变标签的大小。我想保持标签的一致大小并更改字体的大小。 - CodeGuy
1
@reising1:在这种情况下,您也可以使用NSString UIKit附加的方法:sizeWithFont:constrainedToSize:lineBreakMode:但是这种方式有点困难。 - Martin Babacaev
7
自 iOS6 起已被弃用,请使用 myLabel.minimumScaleFactor:10.0/[UIFont labelFontSize]; 进行替换。 - Norbert
XCode告诉我labelFontSize不存在,我尝试了“factLabel.minimumScaleFactor = 8. / self.factLabel.font.pointSize;” - dulgan
@MartinBabacaev 在iOS7+中,numberOfLines = 1不是强制性的。 - JRam13
显示剩余6条评论

76

minimumFontSize 已在 iOS 6 中被弃用。您可以使用 minimumScaleFactor

yourLabel.adjustsFontSizeToFitWidth=YES;
yourLabel.minimumScaleFactor=0.5;

这将根据标签和文本的宽度调整字体大小。


我通常使用0.8,因为即使是0.7看起来也太小了。当然,有些文本可能不适合最小缩放因子0.8,这取决于决定哪个更好看以及何时会变得难以阅读。另一方面,我的应用程序可以旋转,这非常有帮助。 - gnasher729
1
adjustsFontSizeToFitWidth 只有在文本超出容器范围时才会减小字体大小。 - user25

29

单行- 有两种方法,你可以简单地更改。

1- 实用主义 (Swift 3)

只需添加以下代码即可

    yourLabel.numberOfLines = 1;
    yourLabel.minimumScaleFactor = 0.7;
    yourLabel.adjustsFontSizeToFitWidth = true;

2 - 使用UILabel属性检查器

i- Select your label- Set number of lines 1.
ii- Autoshrink-  Select Minimum Font Scale from drop down
iii- Set Minimum Font Scale value as you wish , I have set 0.7 as in below image. (default is 0.5)

在此输入图片描述


2
在Interface Builder中完成会少得多麻烦,所以很棒你提到了这两种方法! - Carl Smith

25
根据 @Eyal Ben Dov 的回答,您可能希望创建一个类别,以便在您的其他应用程序中灵活使用。
注:我已经更新了他的代码,以使其与 iOS 7 兼容。
-头文件
#import <UIKit/UIKit.h>

@interface UILabel (DynamicFontSize)

-(void) adjustFontSizeToFillItsContents;

@end

-实现文件

#import "UILabel+DynamicFontSize.h"

@implementation UILabel (DynamicFontSize)

#define CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE 35
#define CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE 3

-(void) adjustFontSizeToFillItsContents
{
    NSString* text = self.text;

    for (int i = CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE; i>CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE; i--) {

        UIFont *font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
        NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];

        CGRect rectSize = [attributedText boundingRectWithSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];

        if (rectSize.size.height <= self.frame.size.height) {
            self.font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
            break;
        }
    }

}

@end

-使用方法

#import "UILabel+DynamicFontSize.h"

[myUILabel adjustFontSizeToFillItsContents];

干杯


1
如果这段代码对你不起作用,很可能是因为标签的框架尚未设置。尝试在调用此方法之前设置框架(或者如果使用AutoLayout,请调用setNeedsLayout/layoutIfNeeded方法)。 - bmueller
它给出了以下崩溃:“'NSInvalidArgumentException',原因:'NSConcreteAttributedString initWithString :: nil value'” - Mohamed Saleh
这意味着你的NSString不能为nil。我假设如果你想调整字体大小以填充UILabel的内容,你至少需要提供一个文本。 - Paulo Miguel Almeida
这有一个缺点。它在字符之间插入换行符,因此您会看到单词分成不同的行。有没有办法规避这个问题? - Özgür
嗨@Özgür,你尝试过像这样设置标签换行吗?label.lineBreakMode = .ByWordWrapping - Paulo Miguel Almeida
显示剩余4条评论

25

现在是2015年。我必须查找一篇博客文章才能解释如何使用Swift和最新版的iOS和XCode来使多行文本自动调整字体大小。

  1. 将“自动调整字体大小”设置为“最小字体大小”。
  2. 将字体设置为最大可接受的字体大小(我选择了20)。
  3. 将“换行符”从“单词换行”更改为“截断尾部”。

来源: http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/


2
超酷的...那个截断尾部点是最重要的...因为在自动换行布局的情况下,自动布局不会感到减小字体大小的冲动,而当它是截断尾部时,自动布局必须保存文本以免被切割,然后才能调整字体大小。 - GKK
非常正确,如果不截断尾部,则最小字体大小无法生效。 - Gustavo Baiocchi Costa

15

Swift 版本:

textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5

谢谢。看起来这里顺序也很重要。 - Pramod

7
以下是针对UILabel的Swift扩展程序,它运行二分搜索算法来根据标签边界的宽度和高度调整字体大小。已测试适用于iOS 9和自动布局。
用法:将`

啊 - 但是它在自动布局中并不真正起作用;在这种情况下,“sizeToFit”无效。 - Fattie

4

这可能不太复杂,但这应该能够工作。例如,假设您想将您的UILabel限制在120x120以内,并且最大字体大小为28:

magicLabel.numberOfLines = 0;
magicLabel.lineBreakMode = NSLineBreakByWordWrapping;
...
magicLabel.text = text;
    for (int i = 28; i>3; i--) {
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:(CGFloat)i] constrainedToSize:CGSizeMake(120.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
        if (size.height < 120) {
            magicLabel.font = [UIFont systemFontOfSize:(CGFloat)i];
            break;
        }
    }

这似乎相当低效 - 你应该让UILabel动态地调整自身高度以适应一些提供的可用空间。如果你在类似于表视图单元格标题字体计算的情况下运行它,你将会遇到严重的滞后问题。这种方法可能有效,但绝对不推荐使用。 - Zorayr
点赞,因为你是唯一一个实际回答了问题的人。 - Jai

2

只需将 sizeToFit 消息发送给 UITextView,它就会调整自己的高度以适应其文本。它不会更改自己的宽度或起点。

[textViewA1 sizeToFit];

当适合文本的大小超出容器空间时会发生什么?例如,假设您有100个点可用于适应文本视图,在调用sizeToFit后,您的textViewA1变为200个点,结果被裁剪。 - Zorayr

0

Swift 2.0 版本:

private func adapteSizeLabel(label: UILabel, sizeMax: CGFloat) {
     label.numberOfLines = 0
     label.lineBreakMode = NSLineBreakMode.ByWordWrapping
     let maximumLabelSize = CGSizeMake(label.frame.size.width, sizeMax);
     let expectSize = label.sizeThatFits(maximumLabelSize)
     label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, expectSize.width, expectSize.height)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接