show a exactly Height of text in a TextField

277 views Asked by At

I have to program a see test for an optician. So they need that the Numbers are exactly have a specific height. He has a IPad ans streams it to a TV. I know i must consider the PPI of the TV. Here is my Code :

func calcPoints() -> Float {
    // he gives the Visus with a TextField
    let visus = Float(textFieldVisus.text!)
    // Here you put in the PPI of the device
    let ppi = Float(textFieldDPI.text!)
    // Calculate the lenght of the Number
    let lenght = ((0.29 * 5) / visus!) * 5
    // Calculate the Points (because TextFiels work with Points)
    let points = ((ppi! / 25.4) * lenght) * 0.75
    // here you divide with 2 because you have a retina Display on the IPad
    return (points / 2)
}

func passeUIan() {
    // Now i can give the Points to the TextField
    textField1.bounds.size.width = CGFloat(calcPoints())
    textField1.bounds.size.height = CGFloat(calcPoints())
    textField1.font = UIFont(name: (textField1.font?.fontName)!, size: CGFloat(calcPoints()))
}

but when i measure off the lenght on the TV it is wrong. Normaly it must be 7.25mm but it is approximately 9mm. i dont know what is wrong. I search for this problem since 2 weeks...

1

There are 1 answers

2
Code Different On BEST ANSWER

You need to first familiarize yourself with the different font metrics. The font size is usually (but not always) the difference between the ascender and descenders. For your purpose, the height of an uppercase letter is called the "cap height" and the height of a lowercase letter is called the "x-height".

There's no formula to translate the font size to either cap height or x-height. Their relationships different from fonts to fonts, and even variants (bold, italic, small caps, display, book) within a font.

The function below use binary search to look for a point size that matches your desired height (in inches):

// desiredHeight is in inches
func pointSize(inFontName fontName: String, forDesiredCapHeight desiredHeight: CGFloat, ppi: CGFloat) -> CGFloat {
    var minPointSize: CGFloat = 0
    var maxPointSize: CGFloat = 5000
    var pointSize = (minPointSize + maxPointSize) / 2

    // Finding for exact match may not be possible. UIFont may round off
    // the sizes. If it's within 0.01 in (0.26 mm) of the desired height,
    // we consider that good enough
    let tolerance: CGFloat = 0.01

    while let font = UIFont(name: fontName, size: pointSize) {
        let actualHeight = font.capHeight / ppi * UIScreen.main.scale

        if abs(actualHeight - desiredHeight) < tolerance {
            return pointSize
        } else if actualHeight < desiredHeight {
            minPointSize = pointSize
        } else {
            maxPointSize = pointSize
        }

        pointSize = (minPointSize + maxPointSize) / 2
    }

    return 0
}

Example: find the point size that make the capital letter 1-inch tall in Helvetica. (326 is the PPI for iPhone 6 / 6S / 7, which I used to test):

let size = pointSize(inFontName: "Helvetica", forDesiredCapHeight: 1, ppi: 326)
label.font = UIFont(name: fontName, size: size)
label.text = "F"

(tips: a UILabel handles font size much better than a UITextField)