Since sizeWithFont is deprecated, I'm just going to update my original answer to using Swift 4 and .size
//: Playground - noun: a place where people can play
import UIKit
if let font = UIFont(name: "Helvetica", size: 24) {
let fontAttributes = [NSAttributedString.Key.font.font: font]
let text = "Your Text Here"
let size = (text as NSString).size(withAttributes: fontAttributes)
}
The size should be the onscreen size of "Your Text Here" in points.
You can do exactly that via the various sizeWithFont: methods in NSString UIKit Additions. In your case the simplest variant should suffice (since you don't have multi-line labels):
This is for swift 2.3 Version. You can get the width of string.
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)
}
This answer is a much cleaner way to do it using new syntax.
Original Answer
Based on Glenn Howes' excellent answer, I created an extension to calculate the width of a string. If you're doing something like setting the width of a UISegmentedControl, this can set the width based on the segment's title string.
// Set width of segmentedControl
let starString = "⭐️"
let starWidth = starString.widthOfString(usingFont: UIFont.systemFont(ofSize: 14)) + 16
segmentedController.setWidth(starWidth, forSegmentAt: 3)
In SwiftUI, you could not find an easy way to convert UIFont to Font. So the previous answers may not work.
You could use GeometryReader{ geometryProxy in } inside the overlay() modifier to get the Text size. Be careful that if you don't use it inside overlay(), the View will expand to as much as it can.
If you want to pass the variable out, you may need to write a View extension function to do so.
For this very old question/answers, I'm just putting in the current way to do it that always works, which is a combo of answers below.
By always I mean the most common case - which is unfortunately the trickest case - when you're literally modifying something inside of drawText#in rect.
fileprivate extension String {
func realSize(font: UIFont) -> CGSize {
var s = self.size(withAttributes: [NSAttributedString.Key.font: font])
s.width = size.width.rounded(.up)
s.height = size.height.rounded(.up)
return s
}
}
Note that it rounds the size (specifically, up). Why? In most cases you'll want this since typically layouts have even sized points and that's "what you'll need" to match other rendering.
(Note that the difference is absolutely tiny anyway). Try it both ways to see, as you wish.
Hence for example something like
class StableLabel: UILabel {
override var intrinsicContentSize: CGSize {
// we arrange to return some fixed-always size ...
}
override func drawText(in rect: CGRect) {
let painful = text!.realSize(font: font)
// Assuming the size of this label is absolutely fixed by the layout,
// we want to ALWAYS draw the text sitting at the BOTTOM CENTER
// of the fixed size of this label, even as the size is changed.
// For example a focus or such may be changing the point size.
let left = knownSize.width - painful.width) / 2.0
let down = knownSize.height - painful.height)
let r = CGRect(origin: CGPoint(x: left, y: down), size: painful)
super.drawText(in: r)
}