Xavier Bauquet
Xavier Bauquet

Reputation: 730

Label top alignment

I'm trying to put the temperature in my app. I would like to show it like that: enter image description here

But all I'm able to get is that:

enter image description here

I have tried to use this code to align the two label on top:

@IBDesignable class TopAlignedLabel: UILabel {
    override func drawText(in rect: CGRect) {
        if let stringText = text {
            let stringTextAsNSString = stringText as NSString
            let labelStringSize = stringTextAsNSString.boundingRect(with: CGSize(width: self.frame.width,height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).size
        super.drawText(in: CGRect(x:0,y: 0,width: self.frame.width, height:ceil(labelStringSize.height)))
        } else {
            super.drawText(in: rect)
        }
    }
}

It worked on for the '°C' but it's not working for the 25. Can someone help me find a solution to my problem ?

Upvotes: 1

Views: 144

Answers (2)

inorganik
inorganik

Reputation: 25535

A very simple way to solve this is with attributed strings:

let tempText = "25˚C"
let baseFont = UIFont.systemFont(ofSize: 23.0)!
let superscriptFont = UIFont.systemFont(ofSize: 15.0)!
let attrStr = NSMutableAttributedString(string: tempText, attributes: [NSFontAttributeName: baseFont])
attrStr.addAttributes([NSFontAttributeName: superscriptFont, NSBaselineOffsetAttributeName: 10.0], range: NSMakeRange(2,2))

myLabel.attributedText = attrStr

You can keep adding more different attributes on any range you want by using the addAttributes method.

Upvotes: 1

DonMag
DonMag

Reputation: 77638

A font has multiple characteristics, including Ascender, Descender, CapHeight, etc... So what your code gets is not a way to align the character glyphs flush with the top of the label frame, but rather it aligns the Font bounding box to the top of the frame.

Calculating the offset between font metrics might give you what you're after. Here is one example (you can run it in a Playground page):

import UIKit
import PlaygroundSupport

class TestViewController : UIViewController {

    let labelOne: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 60.0)
        label.text = "25"
        label.backgroundColor = .cyan
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 1
        label.textAlignment = .right
        return label
    }()

    let labelTwo: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 24.0)
        label.text = "°C"
        label.backgroundColor = .cyan
        label.translatesAutoresizingMaskIntoConstraints = false
        label.numberOfLines = 1
        return label
    }()


    override func viewDidLoad() {
        super.viewDidLoad()

        // add the scroll view to self.view
        self.view.addSubview(labelOne)
        self.view.addSubview(labelTwo)

        // constrain the scroll view to 8-pts on each side
        labelOne.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
        labelOne.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true

        labelTwo.leftAnchor.constraint(equalTo: labelOne.rightAnchor, constant: 2.0).isActive = true


        if let f1 = labelOne.font, let f2 = labelTwo.font {
            let offset = (f1.ascender - f1.capHeight) - (f2.ascender - f2.capHeight)
            labelTwo.topAnchor.constraint(equalTo: labelOne.topAnchor, constant: offset).isActive = true
        }

    }

}

let vc = TestViewController()
vc.view.backgroundColor = .yellow
PlaygroundPage.current.liveView = vc

And this is the result:

enter image description here

Depending on what font you are actually using, though, that may not be good enough. If so, you'll want to look into CoreText / CTFont / CTFontGetGlyphsForCharacters() / etc.

Upvotes: 1

Related Questions