【问题标题】:How to calculate the width of a text string of a specific font and font-size?如何计算特定字体和字体大小的文本字符串的宽度?
【发布时间】:2010-11-22 09:39:01
【问题描述】:

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

【问题讨论】:

  • 我不知道你会如何使用任何字体类型,但是,如果你使用的是固定宽度的字体,你可以使用字符数来计算。我不完全确定公式。

标签: iphone cocoa-touch uikit


【解决方案1】:

由于 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)
}

大小应为“Your Text Here”的屏幕大小(以磅为单位)。

【讨论】:

  • 感谢您发布此解决方案。我根据你的回答写了一个扩展。它张贴在下面。
  • swift 4中对应的功能是什么?
【解决方案2】:

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];

【讨论】:

  • 注意:sizeWithAttributes: 方法返回小数大小;要使用返回的大小来调整视图大小,您必须使用 ceil 函数将其值提高到最接近的较高整数。
【解决方案3】:

您可以通过NSString UIKit Additions 中的各种sizeWithFont: 方法完全做到这一点。在您的情况下,最简单的变体就足够了(因为您没有多行标签):

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

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

【讨论】:

  • 不应该是UIFont *yourFont = // [UIFont...];虽然?
  • "sizeWithFont:" 已弃用。 wcochran 的回答应该是标记的。
  • 由于您有绿色复选标记,您应该更改答案以使用 sizeWithAttributes。
【解决方案4】:

2019 年 9 月更新

This answer 是一种使用新语法更简洁的方法。

原答案

基于Glenn Howes' excellent answer,我创建了一个扩展来计算字符串的宽度。如果您要设置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)

【讨论】:

  • swift 4 的解决方案是什么?
  • 为什么不只有一个返回大小的函数(CGSize)?为什么要工作两次?
  • @wcochran 已更新。很棒的电话。
  • 我不知道怎么做,但这给了我不正确的尺寸。
  • 没关系,这可行,但根据我的测试,您需要添加 至少 15 的额外填充以防止文本被截断。
【解决方案5】:

Swift-5

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

yourLabel.intrinsicContentSize.width

即使您的字符串之间有自定义间距,如 "T E X T"

【讨论】:

    【解决方案6】:

    Swift 4.2 中的 Oneliner ?

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

    【讨论】:

      【解决方案7】:

      这个简单的 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}
      

      【讨论】:

        【解决方案8】:

        如果您难以通过多行支持获得文本width,那么您可以使用下一个代码(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
        }
        

        如果需要,您可以通过同样的方式找到文本高度(只需切换约束框实现):

        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)
        

        【讨论】:

        • 这正是我所需要的!非常感谢!
        • 你是救生员!谢谢一百万。
        【解决方案9】:

        对于 Swift 5.4

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

        像...一样使用它

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

        【讨论】:

          【解决方案10】:

          斯威夫特 4

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

          【讨论】:

            【解决方案11】:

            这是 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)
                }
            

            【讨论】:

              【解决方案12】:

              不确定这有多有效,但我编写了这个函数,它返回将字符串适合给定宽度的点大小:

              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!))

              【讨论】:

                【解决方案13】:

                我的代码是对 UIFont 进行扩展:(这是 Swift 4.1)

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

                【讨论】:

                  【解决方案14】:

                  Swift5 的 SwiftUI

                  在 SwiftUI 中,您找不到将 UIFont 转换为 Font 的简单方法。所以以前的答案可能不起作用。 您可以在 overlay() 修饰符中使用 GeometryReader{ geometryProxy in } 来获取文本大小。请注意,如果您不在 overlay() 中使用它,View 将尽可能扩展。

                  如果你想把变量传出去,你可能需要写一个视图扩展函数来做。

                  Text("Lat.: \(latitude), Lon.: \(longitude) ")
                      .font(Font.custom("ChalkboardSE-Light",size: 20))
                      .overlay(
                      GeometryReader{ geometryProxy in
                          Image("button_img")
                               .resizable()
                               .frame(width: 10 , height: 10)
                               .offset(x: geometryProxy.size.width)
                               .extensionFunction{ //... }
                                })
                      
                  

                  我几天前从另一个线程复制了扩展功能。

                  extension View{
                      func extensionFunction(_ closure:() -> Void) -> Self{
                          closure()
                          return self
                      }
                      
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-10-08
                    • 1970-01-01
                    • 2012-03-05
                    • 2019-04-08
                    • 2011-11-11
                    • 2012-12-13
                    相关资源
                    最近更新 更多