Mam UILabel, który wyświetla kilka znaków. Na przykład „x”, „y” lub „rpm”. Jak mogę obliczyć szerokość tekstu na etykiecie (nie wykorzystuje całej dostępnej przestrzeni)? Służy do automatycznego układania, gdzie inny widok będzie miał większy prostokąt ramki, jeśli ten UILabel ma mniejszy tekst w środku. Czy istnieją metody obliczania tej szerokości tekstu, gdy określono UIFont i rozmiar czcionki? Nie ma też podziału wiersza i tylko jednej linii.
82
Odpowiedzi:
Możesz to zrobić dokładnie za pomocą różnych
sizeWithFont:
metod w NSString UIKit Additions . W twoim przypadku najprostszy wariant powinien wystarczyć (ponieważ nie masz etykiet wieloliniowych):NSString *someString = @"Hello World"; UIFont *yourFont = // [UIFont ...] CGSize stringBoundingBox = [someString sizeWithFont:yourFont];
Istnieje kilka odmian tej metody, np. niektórzy rozważają tryby łamania linii lub maksymalne rozmiary.
źródło
Ponieważ
sizeWithFont
jest przestarzały, po prostu zaktualizuję moją pierwotną odpowiedź na używanie Swift 4 i.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) }
Powinien to być rozmiar ekranu „Twój tekst tutaj” w punktach.
źródło
sizeWithFont:
jest przestarzały, użyjsizeWithAttributes:
zamiast tego:UIFont *font = [UIFont fontWithName:@"Helvetica" size:30]; NSDictionary *userAttributes = @{NSFontAttributeName: font, NSForegroundColorAttributeName: [UIColor blackColor]}; NSString *text = @"hello"; ... const CGSize textSize = [text sizeWithAttributes: userAttributes];
źródło
sizeWithAttributes:
metoda zwraca rozmiary ułamkowe; aby użyć zwróconego rozmiaru do rozmiaru widoków, należy podnieść jego wartość do najbliższej większej liczby całkowitej za pomocą funkcji ceil.Aktualizacja z września 2019 r
Ta odpowiedź jest dużo czystszym sposobem na zrobienie tego przy użyciu nowej składni.
Oryginalna odpowiedź
W oparciu o doskonałą odpowiedź Glenna Howesa stworzyłem rozszerzenie do obliczania szerokości ciągu. Jeśli robisz coś takiego, jak ustawienie szerokości a
UISegmentedControl
, może to ustawić szerokość na podstawie ciągu tytułu segmentu.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) } }
stosowanie:
// Set width of segmentedControl let starString = "⭐️" let starWidth = starString.widthOfString(usingFont: UIFont.systemFont(ofSize: 14)) + 16 segmentedController.setWidth(starWidth, forSegmentAt: 3)
źródło
Swift-5
Użyj intrinsicContentSize, aby znaleźć wysokość i szerokość tekstu.
yourLabel.intrinsicContentSize.width
To zadziała, nawet jeśli masz niestandardowe odstępy między ciągami, takie jak „TEX T”
źródło
Oneliner w Swift 4.2 🔸
let size = text.size(withAttributes:[.font: UIFont.systemFont(ofSize:18.0)])
źródło
To proste rozszerzenie w Swift działa dobrze.
extension String { func size(OfFont font: UIFont) -> CGSize { return (self as NSString).size(attributes: [NSFontAttributeName: font]) } }
Stosowanie:
let string = "hello world!" let font = UIFont.systemFont(ofSize: 12) let width = string.size(OfFont: font).width // size: {w: 98.912 h: 14.32}
źródło
Szybki 4
extension String { func SizeOf(_ font: UIFont) -> CGSize { return self.size(withAttributes: [NSAttributedStringKey.font: font]) } }
źródło
To jest dla szybkiej wersji 2.3. Możesz uzyskać szerokość sznurka.
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) }
źródło
Jeśli masz problemy z uzyskaniem szerokości tekstu z obsługą wielu wierszy , możesz użyć następnego kodu ( 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 }
I w ten sam sposób możesz znaleźć wysokość tekstu, jeśli musisz (po prostu przełącz implementację constraintBox):
let constraintBox = CGSize(width: maxWidth, height: .greatestFiniteMagnitude)
Lub tutaj jest ujednolicona funkcja do uzyskiwania rozmiaru tekstu z obsługą wielu wierszy:
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 }
Stosowanie:
let textSize = labelSize(for: "SomeText", maxWidth: contentView.bounds.width, maxHeight: .greatestFiniteMagnitude) let textHeight = textSize.height.rounded(.up) let textWidth = textSize.width.rounded(.up)
źródło
Dla 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; } }
Używaj go jak ...
let Str = "ABCDEF" let Font = UIFont.systemFontOfSize(19.0) let SizeOfString = Str.SizeOfString(font: Font!)
źródło
Nie jestem pewien, jak wydajne jest to, ale napisałem tę funkcję, która zwraca rozmiar w punktach, który dopasuje ciąg do określonej szerokości:
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 }
I zostałby użyty w ten sposób:
textView.font = textView.font!.withSize(textView.text!.fontSizeThatFits(targetWidth: view.frame.width, maxFontSize: 50, font: textView.font!))
źródło
Mój kod polega na utworzeniu rozszerzenia UIFont: (To jest Swift 4.1)
extension UIFont { public func textWidth(s: String) -> CGFloat { return s.size(withAttributes: [NSAttributedString.Key.font: self]).width } } // extension UIFont
źródło