如何计算特定字体和字体大小的文本字符串的宽度?


82

我有一个显示一些字符的UILabel。如“ x”,“ y”或“ rpm”。如何计算标签中文本的宽度(它不会占用整个可用空间)?这是用于自动布局的,如果UILabel内部包含较小的文本,则另一个视图将具有较大的框架矩形。指定UIFont和字体大小时,是否有方法来计算文本的宽度?也没有换行符,只有一行。


我不知道如何处理任何字体类型,但是,如果使用的是固定宽度的字体,则可以使用字符数进行计算。我不太确定这个公式。
jgallant

Answers:


73

您可以通过NSString UIKit Additions中的各种sizeWithFont:方法来完成此操作。在您的情况下,最简单的变体就足够了(因为您没有多行标签):

NSString *someString = @"Hello World";
UIFont *yourFont = // [UIFont ...]
CGSize stringBoundingBox = [someString sizeWithFont:yourFont];

例如,此方法有多种变体。有些人考虑换行模式或最大尺寸。


1
应该不是UIFont * yourFont = // [UIFont ...]; 虽然?
PinkFloydRocks

糟糕,是的。
Daniel Rinser 2013年

11
不建议使用“ sizeWithFont:”。wcochran的回答应为已标记。
Ferran Maylinch 2014年

4
由于您具有绿色的选中标记,因此您应该将答案更改为使用sizeWithAttributes。
Glenn Howes

80

由于sizeWithFont已弃用,因此我将更新我的原始答案以使用Swift 4和.size

//: Playground - noun: a place where people can play

import UIKit

if let font = UIFont(name: "Helvetica", size: 24) {
   let fontAttributes = [NSAttributedStringKey.font: font]
   let myText = "Your Text Here"
   let size = (myText as NSString).size(withAttributes: fontAttributes)
}

大小应为“此处您的文本”的屏幕大小(以磅为单位)。


感谢您发布此解决方案。我根据您的回答写了一个扩展名。它发布在下面。
阿德里安

Swift 4的对应功能是什么?
Swayambhu

77

sizeWithFont:现在已弃用,请sizeWithAttributes:改用:

UIFont *font = [UIFont fontWithName:@"Helvetica" size:30];
NSDictionary *userAttributes = @{NSFontAttributeName: font,
                                 NSForegroundColorAttributeName: [UIColor blackColor]};
NSString *text = @"hello";
...
const CGSize textSize = [text sizeWithAttributes: userAttributes];

8
注意:sizeWithAttributes:方法返回小数位数;要使用返回的大小调整视图大小,必须使用ceil函数将其值提高到最接近的较大整数。
艾伦

55

2019年9月更新

这个答案是使用新语法的一种更简洁的方法。

原始答案

基于Glenn Howes的出色回答,我创建了一个扩展来计算字符串的宽度。如果您要进行诸如设置a的宽度之类的操作UISegmentedControl,则可以根据段的标题字符串来设置宽度。

extension String {

    func widthOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        return size.width
    }

    func heightOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        return size.height
    }

    func sizeOfString(usingFont font: UIFont) -> CGSize {
        let fontAttributes = [NSAttributedString.Key.font: font]
        return self.size(withAttributes: fontAttributes)
    }
}

用法:

    // Set width of segmentedControl
    let starString = "⭐️"
    let starWidth = starString.widthOfString(usingFont: UIFont.systemFont(ofSize: 14)) + 16
    segmentedController.setWidth(starWidth, forSegmentAt: 3)

1
快速4的解决方案是什么?
Swayambhu

1
为什么不只是一个返回大小(CGSize)的函数?为什么要工作两次?
wcochran

@wcochran更新。好的电话。
阿德里安

1
我不知道怎么做,但这给了我不正确的尺寸。
马克斯

没关系,这行得通,但是从我的测试来看,您需要添加至少15的附加填充,以防止文本被截断。
马克斯

33

斯威夫特5

使用intrinsicContentSize查找文本的高度和宽度。

yourLabel.intrinsicContentSize.width

即使您在字符串之间具有自定义的间隔(例如“ TEX T”),此方法也将起作用


26

Swift 4.2中的Oneliner

let size = text.size(withAttributes:[.font: UIFont.systemFont(ofSize:18.0)])

6

Swift中的这个简单扩展效果很好。

extension String {
    func size(OfFont font: UIFont) -> CGSize {
        return (self as NSString).size(attributes: [NSFontAttributeName: font])
    }
}

用法:

let string = "hello world!"
let font = UIFont.systemFont(ofSize: 12)
let width = string.size(OfFont: font).width // size: {w: 98.912 h: 14.32}

3

斯威夫特4

extension String {
    func SizeOf(_ font: UIFont) -> CGSize {
        return self.size(withAttributes: [NSAttributedStringKey.font: font])
    }
}

2

这是Swift 2.3版本。您可以获取字符串的宽度。

var sizeOfString = CGSize()
if let font = UIFont(name: "Helvetica", size: 14.0)
    {
        let finalDate = "Your Text Here"
        let fontAttributes = [NSFontAttributeName: font] // it says name, but a UIFont works
        sizeOfString = (finalDate as NSString).sizeWithAttributes(fontAttributes)
    }

2

如果您想通过多行支持来获取文本宽度,则可以使用下一个代码(Swift 5):

func width(text: String, height: CGFloat) -> CGFloat {
    let attributes: [NSAttributedString.Key: Any] = [
        .font: UIFont.systemFont(ofSize: 17)
    ]
    let attributedText = NSAttributedString(string: text, attributes: attributes)
    let constraintBox = CGSize(width: .greatestFiniteMagnitude, height: height)
    let textWidth = attributedText.boundingRect(with: constraintBox, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil).width.rounded(.up)

    return textWidth
}

同样,如果需要,可以找到文本高度(只需切换constraintBox实现):

let constraintBox = CGSize(width: maxWidth, height: .greatestFiniteMagnitude)

或者这是一个统一的功能,可通过多行支持来获取文本大小:

func labelSize(for text: String, maxWidth: CGFloat, maxHeight: CGFloat) -> CGSize {
    let attributes: [NSAttributedString.Key: Any] = [
        .font: UIFont.systemFont(ofSize: 17)
    ]

    let attributedText = NSAttributedString(string: text, attributes: attributes)

    let constraintBox = CGSize(width: maxWidth, height: maxHeight)
    let rect = attributedText.boundingRect(with: constraintBox, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil).integral

    return rect.size
}

用法:

let textSize = labelSize(for: "SomeText", maxWidth: contentView.bounds.width, maxHeight: .greatestFiniteMagnitude)
let textHeight = textSize.height.rounded(.up)
let textWidth = textSize.width.rounded(.up)

1

对于Swift 3.0+

extension String {
    func SizeOf_String( font: UIFont) -> CGSize {
        let fontAttribute = [NSFontAttributeName: font]
        let size = self.size(attributes: fontAttribute)  // for Single Line
       return size;
   }
}

像...那样使用

        let Str = "ABCDEF"
        let Font =  UIFont.systemFontOfSize(19.0)
        let SizeOfString = Str.SizeOfString(font: Font!)

1

不确定这样做的效率如何,但我编写了此函数,该函数返回的点大小将使字符串适合给定宽度:

func fontSizeThatFits(targetWidth: CGFloat, maxFontSize: CGFloat, font: UIFont) -> CGFloat {
    var variableFont = font.withSize(maxFontSize)
    var currentWidth = self.size(withAttributes: [NSAttributedString.Key.font:variableFont]).width

    while currentWidth > targetWidth {
        variableFont = variableFont.withSize(variableFont.pointSize - 1)
        currentWidth = self.size(withAttributes: [NSAttributedString.Key.font:variableFont]).width
    }

    return variableFont.pointSize
}

它会像这样使用:

textView.font = textView.font!.withSize(textView.text!.fontSizeThatFits(targetWidth: view.frame.width, maxFontSize: 50, font: textView.font!))


0

我做代码的方式是扩展UIFont :(这是Swift 4.1)

extension UIFont {


    public func textWidth(s: String) -> CGFloat
    {
        return s.size(withAttributes: [NSAttributedString.Key.font: self]).width
    }

} // extension UIFont
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.