[
I'm looking to make a pixelPerfect UI. My designer gave me a few requirements for a specific font. I'm trying to implement them but I've run into some issues with paragraphStyle. All text first baselines must be positioned on a grid. When setting maximumLineHeight for my Title to 24 (2x grid) everything is fine. However, my bodyText needs a lineHeight of 16. This cuts off the top of the first line.
I've tried setting the label height, this just adds layout conflicts. I've tried setting the firstBaseline constraint to a grid measure away from it's own top. To no avail. I've also overridden the UILabel's draw method to add some additional top padding. However this throws off the fristBaseline constraint usage in my code by whatever padding I added. Very dirty and only the ultimate last resort.
import Foundation
public class UILabelBody: UILabel {
override public var text: String? {
didSet {
let attributedString = NSMutableAttributedString(string: self.text!)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.maximumLineHeight = 16
attributedString.addAttributes([
NSAttributedString.Key.kern: 0.4,
NSAttributedString.Key.paragraphStyle : paragraphStyle],
range: NSMakeRange(0, attributedString.length))
self.attributedText = attributedString
}
}
public init() {
super.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
setup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setup() {
self.font = UIFont(name: "Oxygen", size: 16)
self.textColor = UIColor(hexString: "1F1F1F")
}
}
Here's the class that i set the constraints: private func setup() {
self.addSubview(contentBox)
self.addSubview(imageView)
self.addSubview(title)
self.addSubview(body)
imageView.backgroundColor = UIColor.yellow.withAlphaComponent(0.8)
contentBox.backgroundColor = UIColor.red.withAlphaComponent(0.1)
title.backgroundColor = UIColor.orange.withAlphaComponent(0.2)
let padding = Layout.grid(1.5)
let highPriority = UILayoutPriority(1000)
let lowPrioririty = UILayoutPriority(100)
let titleFirstBaseline = title.firstBaselineAnchor.constraint(equalTo: contentBox.topAnchor, constant: Layout.grid(2.5))
let bodyFirstBaseLine = body.firstBaselineAnchor.constraint(equalTo: title.lastBaselineAnchor, constant: Layout.grid(2))
let selfHeight = self.heightAnchor.constraint(equalToConstant: Layout.grid(28))
let selfWidth = self.widthAnchor.constraint(equalToConstant: Layout.grid(30))
selfWidth.priority = highPriority
selfHeight.priority = lowPrioririty
titleFirstBaseline.priority = highPriority
bodyFirstBaseLine.priority = highPriority
NSLayoutConstraint.activate([
selfWidth,
selfHeight,
contentBox.topAnchor.constraint(equalTo: self.topAnchor, constant: padding),
contentBox.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: padding),
contentBox.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -padding),
contentBox.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -padding),
imageView.leadingAnchor.constraint(equalTo: contentBox.leadingAnchor),
imageView.topAnchor.constraint(equalTo: contentBox.topAnchor),
imageView.widthAnchor.constraint(equalToConstant: Layout.grid(4)),
imageView.heightAnchor.constraint(equalToConstant: Layout.grid(4)),
title.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: padding),
titleFirstBaseline,
title.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -padding),
bodyFirstBaseLine,
body.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: padding),
body.bottomAnchor.constraint(equalTo: self.contentBox.bottomAnchor),
body.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -padding),
])
}
After spending a few hours in the torture chamber I finally figured it out! The issue was the font itself. It was an .otf and not a .ttf. Because of this swift did not understand the font's internal lineheight and just cut it off. After switching to .ttf the issue was resolved