Belirli bir yazı tipi ve yazı tipi boyutundaki bir metin dizesinin genişliği nasıl hesaplanır?


82

Bazı karakterleri gösteren bir UILabel var. "X", "y" veya "rpm" gibi. Etiketteki metnin genişliğini nasıl hesaplayabilirim (tüm mevcut alanı kullanmaz)? Bu, UILabel'in içinde daha küçük bir metin varsa, başka bir görünümün daha büyük bir çerçeve dikdörtgenine sahip olacağı otomatik yerleşim içindir. Bir UIFont ve yazı tipi boyutu belirtildiğinde metnin bu genişliğini hesaplamanın yöntemleri var mı? Ayrıca satır sonu yok ve yalnızca tek bir satır var.


Bunu herhangi bir yazı tipiyle nasıl yapardınız bilmiyorum, ancak sabit genişlikte bir yazı tipi kullanıyorsanız, karakter sayısını kullanarak hesaplayabilirsiniz. Formülden tam olarak emin değilim.
jgallant

Yanıtlar:


74

NSString UIKit Eklentilerindeki çeşitli sizeWithFont:yöntemlerle tam olarak bunu yapabilirsiniz . Sizin durumunuzda en basit varyant yeterli olmalıdır (çünkü çok satırlı etiketleriniz yoktur):

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

Bu yöntemin birkaç çeşidi vardır, örn. bazıları satır sonu modlarını veya maksimum boyutları dikkate alır.


1
UIFont * yourFont = // [UIFont ...]; rağmen?
PinkFloydRocks

11
"sizeWithFont:" kullanımdan kaldırıldı. Wcochran tarafından verilen cevap işaretli olmalıdır.
Ferran Maylinch

4
Yeşil onay işaretine sahip olduğunuz için, yanıtınızı sizeWithAttributes kullanmak için değiştirmelisiniz.
Glenn Howes

80

Kullanımdan sizeWithFontkaldırıldığından, Swift 4'ü kullanma konusundaki orijinal cevabımı güncelleyeceğim ve.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)
}

Boyut, "Buradaki Metniniz" ekran boyutunun puan cinsinden boyutu olmalıdır.


Bu çözümü gönderdiğiniz için teşekkür ederiz. Cevabınıza göre bir uzatma yazdım. Aşağıda yayınlanmıştır.
Adrian

Swift 4'teki karşılık gelen işlev ne olacak?
Swayambhu

77

sizeWithFont:artık kullanımdan kaldırıldı, sizeWithAttributes:bunun yerine şunu kullanın:

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

8
Not: sizeWithAttributes:yöntem kesirli boyutları döndürür; boyut görünümlerine döndürülen bir boyutu kullanmak için, ceil işlevini kullanarak değerini en yakın yüksek tam sayıya yükseltmelisiniz.
Allen

55

Eylül 2019 Güncellemesi

Bu cevap , yeni sözdizimi kullanarak yapmanın çok daha temiz bir yoludur.

Orijinal Cevap

Glenn Howes'in mükemmel cevabına dayanarak, bir dizenin genişliğini hesaplamak için bir uzantı oluşturdum. A'nın genişliğini ayarlamak gibi bir şey yapıyorsanız UISegmentedControl, bu genişliği segmentin başlık dizesine göre ayarlayabilir.

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

kullanım:

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

1
Swift 4 için çözüm ne olacak?
Swayambhu

1
Neden boyut döndüren tek bir işlev (CGSize) değil? Neden işi iki kez yapıyor?
wcochran

@wcochran Güncellendi. Harika çağrı.
Adrian

1
Nasıl olduğunu bilmiyorum ama bu bana yanlış beden veriyor.
Max

Boşver, bu işe yarıyor, ancak testlerimden , metnin kesilmesini önlemek için en az 15 ek dolgu eklemeniz gerekiyor .
Maks.

33

Swift-5

Metin yüksekliğini ve genişliğini bulmak için intrinsicContentSize kullanın.

yourLabel.intrinsicContentSize.width

Bu, dizeniz arasında "TEX T" gibi özel boşluklar olsa bile çalışacaktır.


28

Swift 4.2'de Oneliner 🔸

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

6

Swift'deki bu basit uzantı iyi çalışıyor.

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

Kullanım:

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

Bu, hızlı 2.3 Sürümü içindir. İpin genişliğini elde edebilirsiniz.

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

Metin almak için mücadele ediyorsanız genişliği ile satırlı destek sonraki kod (kullanabilmesi için, 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
}

Ve gerekirse metin yüksekliğini bulabileceğiniz gibi (sadece constraintBox uygulamasını değiştirin):

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

Veya burada çok satırlı destekle metin boyutu elde etmek için birleşik bir işlev var :

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
}

Kullanım:

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

1

İçin 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;
   }
}

Şunun gibi kullanın ...

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

1

Bunun ne kadar verimli olduğundan emin değilim, ancak bir dizgeye belirli bir genişliğe uyacak nokta boyutunu döndüren bu işlevi yazdım:

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
}

Ve şu şekilde kullanılacaktır:

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


0

Bunu yapma şeklim, kodum UIFont'un bir uzantısı yapmak: (Bu Swift 4.1)

extension UIFont {


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

} // extension UIFont
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.