调整UILabel高度以适应文本

131

我有一些标签,我希望将它们的高度调整为文本的高度,这是我现在编写的代码

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

编辑:

问题并不在这段代码中,所以我的修复方法在问题本身。对于其他人仍然可能是有用的!


看一下NSString UIKit的附加功能,那里有方法可以计算所需的大小,而不需要创建UILabel。 - Vladimir Gritsenko
@VladimirGritsenko,“sizeWithFont”方法在Swift中不可用 :( - TheBurgerShot
我承认我不是Swift专家,但我相信你可以添加自己的桥接方法。这仍然比创建UILabel来计算大小要好得多。 - Vladimir Gritsenko
@TheBurgerShot sizeWithFont 在 Swift 的 String 中可能不可用,但在 NSString 上是可用的。你仍然可以在 NSString 上调用它。 - Anorak
最终,错误是另外一件事情,与这个方法无关。虽然这可能仍然对其他人有帮助。 - TheBurgerShot
18个回答

213

我刚将其放入游乐场并且它对我有效。

针对Swift 4.0进行更新

import UIKit

 func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

let font = UIFont(name: "Helvetica", size: 20.0)

var height = heightForView("This is just a load of text", font: font, width: 100.0)

Swift 3:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    return label.frame.height
}

enter image description here


这在我的 playground 中也可以正常工作,错误似乎并不发生在特定的位置,当我删除对该方法的使用时,它会抱怨一些 println 或只有注释的行(然后它也会显示 EXC_BAD_ACCESS code=2)。 - TheBurgerShot
6
在 XCode 6.1 中,它在游乐场中运行正常,但在视图控制器中无法按预期发生大小调整。 - Unome
2
我有点犹豫是否要为每个大小创建一个新的 UILabel;如果在 layoutSubviews 中使用此方法,并且倾向于在完整布局期间多次调用它,则额外的对象创建可能会引入明显的延迟,特别是在滚动期间。 - Zorayr
让textRect = textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil) - Siddharth Pancholi
我无法在我的视图控制器中调用这个函数...你能给我建议可能的原因吗? - Rouny
这将不会按照我的预期工作,我想要标签的大小与我的视图相等,并且高度根据文本动态调整,并将其放置在视图底部,我应该如何做到这一点? - Saeed Rahmatolahi

69
如果您正在使用AutoLayout,您可以通过仅配置UI来调整UILabel的高度。
对于iOS8或更高版本:
- 为您的UILabel设置前导/后续约束 - 并将UILabel的行数从1更改为0

enter image description here

iOS7用户请注意

  • 首先,您需要为UILabel添加高度属性
  • 然后,将关系从Equal修改为Greater than or Equal

enter image description here

  • 最后,将UILabel的行数从1改为0

enter image description here

你的 UILabel 将根据文本自动增加高度。

2
如果标签位于单元格内,您何时以及如何相应增加单元格高度? - oyalhi
1
@oyalhi,如果您的标签位于tableview单元格内,请参阅我的另一篇帖子https://dev59.com/QWkw5IYBdhLWcg3wirCs#36277840。 - Linh
3
这对我非常有效!设置好约束条件,它就能正常工作! - Bill Thompson
2
对我无效...UILabel中的单词"Label"使高度=20。设置后仍保持为20。 - gadget00
不知道“add contains height for UILabel”是什么意思,而且UIBuilder中也没有“Height Constraint”部分与第一个项目(如图所示)? - John Pitts

11

我有一个强大的工作解决方案。

在layoutSubviews方法中:

title.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 0)
title.sizeToFit()
title.frame.size = title.bounds.size

文本设置器:

title.text = newValue
setNeedsLayout()

更新: 当然,使用这个UILabel设置:

title.lineBreakMode = .byWordWrapping
title.numberOfLines = 0

证明了。谢谢! - Jatezzz

11
在Swift 4.1和Xcode 9.4.1中,
仅需3个步骤Step 1)
//To calculate height for label based on text size and width
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat {
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

第二步)

//Call this function
let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300)
print(height)//Output : 41.0

第三步)

//This is your label
let proNameLbl = UILabel(frame: CGRect(x: 0, y: 20, width: 300, height: height))
proNameLbl.text = "This is your text"
proNameLbl.font = UIFont.systemFont(ofSize: 17)
proNameLbl.numberOfLines = 0
proNameLbl.lineBreakMode = .byWordWrapping
infoView.addSubview(proNameLbl)

10

如果您需要,我可以创建这个扩展。

extension UILabel {
    func setSizeFont (sizeFont: CGFloat) {
        self.font =  UIFont(name: self.font.fontName, size: sizeFont)!
        self.sizeToFit()
    }
}

8

根据Anorak的回答,我也同意Zorayr的担忧,所以我添加了几行代码来删除UILabel并仅返回CGFloat,我不知道它是否有用,因为原始代码没有添加UIabel,但它不会出错,所以我正在使用以下代码:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{

    var currHeight:CGFloat!

    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    currHeight = label.frame.height
    label.removeFromSuperview()

    return currHeight
}

6

只需设置:

label.numberOfLines = 0

41
这并不会使UILabel调整其高度。 - TheBurgerShot

6
由 Anorak 提出的解决方案是,将其作为 UILabel 的扩展中的计算属性:
extension UILabel
{
var optimalHeight : CGFloat
    {
        get
        {
            let label = UILabel(frame: CGRectMake(0, 0, self.frame.width, CGFloat.max))
            label.numberOfLines = 0
            label.lineBreakMode = self.lineBreakMode
            label.font = self.font
            label.text = self.text

            label.sizeToFit()

            return label.frame.height
         }
    }
}

用法:

self.brandModelLabel.frame.size.height = self.brandModelLabel.optimalHeight

2
无法赋值给属性:'height' 是只读属性。 - Amg91

4

继@Anorak的回答之后,我将此扩展添加到了String并将插入作为参数发送,因为很多时候您需要对文本进行填充。无论如何,也许有些人会发现这很有用。

extension String {

    func heightForWithFont(font: UIFont, width: CGFloat, insets: UIEdgeInsets) -> CGFloat {

        let label:UILabel = UILabel(frame: CGRectMake(0, 0, width + insets.left + insets.right, CGFloat.max))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.ByWordWrapping
        label.font = font
        label.text = self

        label.sizeToFit()
        return label.frame.height + insets.top + insets.bottom
    }
}

label.lineBreakMode = NSLineBreakMode.ByWordWrapping 这行代码帮了我,谢谢。 - Coder_A_D

3

Swift 4.0

这段代码创建了一个UILabel,并将其框架(位置和大小)设置为(x: 70, y: 60, 宽度:UIScreen.main.bounds.width - 80, 高度:30)。

messageLabel.text = message

messageLabel.lineBreakMode = .byWordWrapping //in versions below swift 3 (messageLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping)    
messageLabel.numberOfLines = 0 //To write any number of lines within a label scope

messageLabel.textAlignment = .center

messageLabel.textColor = UIColor.white

messageLabel.font = messageLabel.font.withSize(12)

messageLabel.sizeToFit()

Blockquote NSParagraphStyle.LineBreakMode适用于整个段落,而不是段落中的单词。该属性在正常绘制和字体大小必须缩小以适应标签边界框中的文本的情况下均有效。默认情况下,此属性设置为byTruncatingTail。

此链接描述了使用Storyboard完成相同操作的方法


2
仅提供代码的答案并不是一个好的做法。请考虑添加一些解释,说明您的答案如何回答问题。 - Yannis

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