UILabel没有自动缩小文本以适应标签大小。

134

我有一个奇怪的问题,已经花了超过8个小时在解决它了... 根据情况,我必须动态计算 UILabels 的大小。例如,我的 UIViewController 接收到一个事件,我会更改 UILabels 的大小,从大到小。我的 UILabel 的大小变小了,我得到了正确需要的大小,但是我的 UILabel 的文字仍然是相同的,字体大小也没有改变。我需要字体变小,让整个文本适合 UILabels。那么问题是如何使文本适应我的标签与 autoshrinking 或类似的东西?

在我的 xib 中,UILabelsautoshrink 已被选中,行数 也设置为0,并且我的字符串具有换行符(\n),我已选择 linebreakmodewordwrap。也许有人曾经和我一样处于同样的情况,可以帮助我吗?我会非常感激。

提前感谢!

编辑:UILabels 最小字体大小设置为10


请问您设置的标签字体的最小尺寸是多少?请添加。 - AJPatel
17个回答

179

如果您仍在寻找更好的解决方案,我认为这是您想要的:

布尔值,指示字体大小是否应减小以使标题字符串适合标签的边界矩形(仅当将numberOfLines属性设置为 1时,此属性才有效)。

设置此属性时,必须同时设置minimumScaleFactor(一个很好的默认值是0.5)。

Swift

var adjustsFontSizeToFitWidth: Bool { get set }

Objective-C

@property(nonatomic) BOOL adjustsFontSizeToFitWidth;

一个布尔值,指示是否应该调整字母间的间距以适应标签边界矩形内的字符串。

Swift

var allowsDefaultTighteningForTruncation: Bool { get set }

Objective-C

@property(nonatomic) BOOL allowsDefaultTighteningForTruncation;

源代码.


20
作为旁注,minimumFontSize 在 iOS 6.0 中已被废弃,请改用 minimumScaleFactor - lester
15
是的,UILabel 中的自动收缩不适用于多行文本。 试想一下:你有一个多行文本,你想将它缩小以适应宽度。那么它应该将整个文本缩小到适合一行,还是单词保持在同一行并缩小以适应每个宽度?后者是最常见的情况,但不要忘记单词也被设置为按照多行排列。即使禁用了文本的自动排列,你仍然需要面对每行文本具有不同字体大小的问题,因为不是每个单词都适合宽度。 - lester
2
我认为这里带有类别的答案非常好,甚至可能是您已经实现的内容。这绝对是Apple API中缺少的东西,或者他们可能只是没有看到缩小应该是多行静态文本的常见用例。 - lester
4
@lester,它应该缩小文本以便在标签声明的行数内完整显示,而不需要尝试使每行具有不同的大小。我真的很惊讶它无法解决这个问题。因此,如果我有一个(潜在的)长字符串要显示,我只能选择将其分为多行或自动调整大小,而不能两者兼备。这太美妙了。 - devios1
1
@lester 这很容易。苹果自己的 CoreText 库(驱动 UIKit)已经内置了该功能。在 IB/iOS 中多行标签丢失/损坏的明显原因是,当他们将 CoreText 添加到 iOS 时,苹果忘记修复它。他们的 bug 跟踪非常糟糕。 - Adam
显示剩余3条评论

132

以下是我如何使UILabel的自动调整字号功能起作用(尤其是适合在4S设备和6S Plus Storyboard中适应标签字体高度)在iOS 9.2,Xcode 7.2中…

输入图像说明

  • 行数为0
  • 换行: 裁剪
  • 自动调整字号: 最小字体比例0.25

16
这是标签实际缩小所需的三个要素,我缺少了剪辑折行设置。此外,如果它相邻于其他标签(这些标签也可能自动缩小),则需要设置压缩/挤压优先级或给出明确的宽度或高度约束。这应该是目前被接受的答案。 - Korey Hinton
确保您的标签具有所有约束条件,特别是前导和尾随。 - Mashhadi
2
我已经尝试在Xcode8中使用相同的选项,但没有效果。请问有谁对此有想法,能够提供帮助吗? - Ganesh

85

minimumFontSize在iOS 6中已被弃用。

因此,请使用minimumScaleFactor代替minmimumFontSize

lbl.adjustsFontSizeToFitWidth = YES
lbl.minimumScaleFactor = 0.5

Swift 5

lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5

1
@AntonMatosov,不,它没有! - Iulian Onofrei
2
是的,它可以(现在) - 如果您还将换行设置为截断尾部而不是单词换行... - TheEye

23

我的解决方案是将布尔标签label.adjustsFontSizeToFitWidth设置为YES; 但是,您必须在界面构建器中将Word Wrapping开关切换到"CLIP"。 然后自动调整标签大小。这非常重要。


3
只有当我从“自动换行”改为“裁剪”时,自动缩小才能对我起作用。 - NicJ
当我将自动换行改为裁剪时,实际上我能够在一个零行的标签中调整大小。如果这个功能被记录下来就好了。 - DesignatedNerd

13

在 Swift 3 中(以编程方式),我不得不这样做:

let lbl = UILabel()
lbl.numberOfLines = 0
lbl.lineBreakMode = .byClipping
lbl.adjustsFontSizeToFitWidth = true
lbl.minimumScaleFactor = 0.5
lbl.font = UIFont.systemFont(ofSize: 15)

5
你可以像这样编写代码。
UILabel *reviews = [[UILabel alloc]initWithFrame:CGRectMake(14, 13,270,30)];//Set frame
reviews.numberOfLines=0;
reviews.textAlignment = UITextAlignmentLeft;
reviews.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size:12];
reviews.textColor=[UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.8]; 
reviews.backgroundColor=[UIColor clearColor];

您可以像这样计算行数
CGSize maxlblSize = CGSizeMake(270,9999);
CGSize totalSize = [reviews.text sizeWithFont:reviews.font 
              constrainedToSize:maxlblSize lineBreakMode:reviews.lineBreakMode];

CGRect newFrame =reviews.frame;
newFrame.size.height = totalSize.height;
reviews.frame = newFrame;

CGFloat reviewlblheight = totalSize.height;

int lines=reviewlblheight/12;//12 is the font size of label

UILabel *lbl=[[UILabel alloc]init];
lbl.frame=CGRectMake(140,220 , 100, 25);//set frame as your requirement
lbl.font=[UIFont fontWithName:@"Arial" size:20];
[lbl setAutoresizingMask:UIViewContentModeScaleAspectFill];
[lbl setLineBreakMode:UILineBreakModeClip];
lbl.adjustsFontSizeToFitWidth=YES;//This is main for shrinking font
lbl.text=@"HelloHelloHello";

希望这能帮到你:-) 等待您的回复

那么如果我将标签的行数设置为固定值,文本会自动缩小吗? - Lukas
如果您的内容超出宽度,则会换到下一行。 Translated: - Birju
嘿,我按照你建议的做了,但它不起作用,为什么行数会对我有帮助? - Lukas
你说得对,我试过了,它没什么用。但是我为你找到了解决方案,像这样做,我的下一个答案会告诉你。 - Birju
lbl.adjustsFontSizeToFitWidth=YES; 这个对我有用! - Developer

4
这是一个很好的问题,因为现在似乎应该将其作为内置的UIKit功能或相关框架的一部分。这是一个很好的可视化示例:

Font resizing animation

没有简单的方法可以解决这个问题,但肯定是可能的。一种方法是编程尝试不同的字体大小,直到找到一个与视图边界相当接近的字体大小。您可以使用NSStringNSAttributedStringboundingRect()函数来完成此操作。例如:
let string = "This is a test"
let infiniteSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height:CGFloat.greatestFiniteMagnitude)
let size = string.boundingRect(with: infiniteSize, options: [], attributes: [.font: UIFont.systemFont(ofSize: avgSize)] context: nil).size

你可以使用二分查找来提高效率,而不是采用完全的蛮力方法。此外,如果你想要一个真正健壮的解决方案,还有一些比较复杂的考虑因素,包括正确的换行和iOS字体缓存性能。
如果你只关心在屏幕上以简单的方式显示文本,我已经使用Swift开发了一个健壮的实现,并在生产应用中使用它。它是一个UIView子类,对于任何输入文本(包括多行文本),都具有高效的自动字体缩放功能。要使用它,你只需要这样做:
let view = AKTextView()
// Use a simple or fancy NSAttributedString
view.attributedText = .init(string: "Some text here")
// Add to the view hierarchy somewhere

就是这样!您可以在此处找到完整的源代码:https://github.com/FlickType/AccessibilityKit

希望这能有所帮助!


1
2018年11月:似乎FlickType和AccessibilityKit已经变成了私有或已被删除。 - Chris Paveglio

4
最终我没有找到答案。而且我认为自动调整大小无法用于多行。最后,我使用了此链接中的建议: 在UILabel上实现多行文本自动调整大小 解决方案是计算给定宽度下文本的高度,如果文本太大,则缩小字体大小,然后再次执行同样的操作,直到高度等于或小于所需大小。
我不明白为什么这么难实现。如果我错了,欢迎任何人纠正我 :)

根据其他答案,关键缺失的是您需要将“换行”设置为“剪辑”。这似乎有些违反直觉,但这是使UILabel按您想要的方式自动缩小所必需的。这适用于多行UILabel。 - Duncan Babbage

4

这是针对在 Xcode 8.2.1(8C1002)上运行 Swift 3 的情况。

我发现最好的解决方案是在你的 Storyboard 或 IB 中为标签设置固定宽度。使用边缘约束设置你的约束条件。在你的 viewDidLoad 中添加以下代码:

override func viewDidLoad() {
            super.viewDidLoad()

            label.numberOfLines = 1
            label.adjustsFontSizeToFitWidth = true
            label.minimumScaleFactor = 0.5
        }

标签限制对齐边缘

固定宽度标签约束到边缘

属性检查器

这个方法非常实用,它不会溢出到新的一行,并且可以自动调整标签的宽度来适应文本内容,同时不会出现任何奇怪的问题,适用于Swift3。


3
在iOS 9中,我只需要:
  1. 从标签左侧和右侧添加约束到父视图。
  2. 在IB中将换行模式设置为裁剪。
  3. 在IB中将行数设置为1。
有人建议将行数设置为0,但对我来说,这只会使标签变成多行...

这对我很有帮助。我刚刚选择了一个静态单元格中的 UILabelUITextField,然后点击了“解决自动布局问题”和“添加缺失的约束条件”。一切都排列整齐了,但是 Autoshrink 需要知道标签的距离,而“添加缺失的约束条件”没有为此添加约束条件。 - Adrian

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