Làm thế nào để tính toán chiều rộng của một chuỗi văn bản của một phông chữ và kích thước phông chữ cụ thể?


82

Tôi có một UILabel hiển thị một số ký tự. Như "x", "y" hoặc "rpm". Làm cách nào để tính chiều rộng của văn bản trong nhãn (nó không chiếm toàn bộ không gian có sẵn)? Điều này dành cho bố cục tự động, trong đó một chế độ xem khác sẽ có hình chữ nhật khung lớn hơn nếu Nhãn đó có văn bản nhỏ hơn bên trong. Có phương pháp nào để tính toán chiều rộng đó của văn bản khi UIFont và kích thước phông chữ được chỉ định không? Cũng không có ngắt dòng và chỉ có một dòng duy nhất.


Tôi không biết bạn sẽ làm như thế nào với bất kỳ loại phông chữ nào, tuy nhiên, nếu bạn đang sử dụng phông chữ có chiều rộng cố định, bạn có thể tính toán bằng cách sử dụng số ký tự. Tôi không hoàn toàn chắc chắn về công thức.
jgallant

Câu trả lời:


73

Bạn có thể thực hiện chính xác điều đó thông qua các sizeWithFont:phương pháp khác nhau trong NSString UIKit Additions . Trong trường hợp của bạn, biến thể đơn giản nhất là đủ (vì bạn không có nhãn nhiều dòng):

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

Có một số biến thể của phương pháp này, ví dụ. một số xem xét các chế độ ngắt dòng hoặc kích thước tối đa.


1
Không nên là UIFont * yourFont = // [UIFont ...]; Tuy nhiên?
PinkFloydRocks

Rất tiếc, vâng, chắc chắn .. Đã sửa.
Daniel Rinser

11
"sizeWithFont:" không được dùng nữa. Câu trả lời của wcochran nên được đánh dấu.
Ferran Maylinch

4
Vì bạn có dấu kiểm màu xanh lá cây, bạn nên thay đổi câu trả lời của mình để sử dụng sizeWithAttributes.
Glenn Howes

80

sizeWithFontkhông được dùng nữa nên tôi sẽ cập nhật câu trả lời ban đầu của mình để sử dụng Swift 4 và.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)
}

Kích thước phải là kích thước trên màn hình của "Văn bản của bạn ở đây" tính bằng điểm.


Cảm ơn bạn đã đăng giải pháp này. Tôi đã viết một phần mở rộng dựa trên câu trả lời của bạn. Nó được đăng bên dưới.
Adrian

Chức năng tương ứng trong swift 4 sẽ là gì?
Swayambhu

77

sizeWithFont:hiện không được dùng nữa, hãy sử dụng sizeWithAttributes:thay thế:

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

8
Lưu ý: sizeWithAttributes:phương thức trả về kích thước phân số; để sử dụng kích thước được trả về cho các chế độ xem kích thước, bạn phải nâng giá trị của nó lên số nguyên cao hơn gần nhất bằng cách sử dụng hàm ceil.
Allen

55

Cập nhật tháng 9 năm 2019

Câu trả lời này này là một cách dễ dàng hơn để làm điều đó bằng cách sử dụng cú pháp mới.

Câu trả lời gốc

Dựa trên câu trả lời xuất sắc của Glenn Howes , tôi đã tạo một phần mở rộng để tính chiều rộng của một chuỗi. Nếu bạn đang làm điều gì đó như đặt chiều rộng của a UISegmentedControl, điều này có thể đặt chiều rộng dựa trên chuỗi tiêu đề của phân đoạn.

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

sử dụng:

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

1
Giải pháp cho swift 4 sẽ là gì?
Swayambhu

1
Tại sao không chỉ một hàm trả về kích thước (CGSize)? Tại sao làm việc hai lần?
wcochran

@wcochran Đã cập nhật. Cuộc gọi tuyệt vời.
Adrian

1
Tôi không biết làm thế nào, nhưng điều này cho tôi kích thước không chính xác.
Tối đa

Đừng bận tâm, điều này hoạt động nhưng từ các thử nghiệm của tôi, bạn cần thêm khoảng đệm bổ sung ít nhất là 15 để ngăn văn bản bị cắt ngắn.
Tối đa

33

Swift-5

Sử dụng nội tạiContentSize để tìm chiều cao và chiều rộng của văn bản.

yourLabel.intrinsicContentSize.width

Điều này sẽ hoạt động ngay cả khi bạn có khoảng cách tùy chỉnh giữa chuỗi của mình như "TEX T"


26

Oneliner trong Swift 4.2 🔸

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

6

Tiện ích mở rộng đơn giản này trong Swift hoạt động tốt.

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

Sử dụng:

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

Swift 4

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

2

Đây là phiên bản 2.3 nhanh chóng. Bạn có thể lấy chiều rộng của chuỗi.

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

Nếu bạn đang đấu tranh để có được chiều rộng văn bản với hỗ trợ nhiều dòng , vì vậy bạn có thể sử dụng mã tiếp theo ( 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
}

Và theo cách tương tự, bạn có thể tìm chiều cao văn bản nếu cần (chỉ cần chuyển đổi việc triển khai constraintBox):

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

Hoặc đây là một chức năng thống nhất để có được kích thước văn bản với hỗ trợ đa dòng:

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
}

Sử dụng:

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

1

Đối với 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;
   }
}

Sử dụng nó như ...

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

1

Không chắc điều này hiệu quả đến mức nào, nhưng tôi đã viết hàm này trả về kích thước điểm sẽ phù hợp với một chuỗi với chiều rộng nhất định:

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
}

Và nó sẽ được sử dụng như thế này:

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


0

Cách tôi đang thực hiện mã của tôi là tạo một phần mở rộng của UIFont: (Đây là Swift 4.1)

extension UIFont {


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

} // extension UIFont
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.