I am producing a fancy NSAttributedString utilizing a number of kinds, fonts, and even inline picture attachments (icons), and I am attempting to calculate the precise top it will take when displayed in a UILabel or related view with a set width.
Here is my attributed string constructing perform:
func getStringBasic(obj: TemplateModel) -> NSAttributedString {
let attributedString = NSMutableAttributedString()
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 6
let titleAttributes: [NSAttributedString.Key: Any] = [
.font: ThemeFont.splineBold(size: 16),
.foregroundColor: ThemeColor.textBlack,
.paragraphStyle: paragraphStyle
]
let otherAttributes: [NSAttributedString.Key: Any] = [
.font: ThemeFont.splineRegular(size: 10),
.foregroundColor: ThemeColor.textBlack,
.paragraphStyle: paragraphStyle
]
let paragraphStyle2 = NSMutableParagraphStyle()
paragraphStyle2.lineSpacing = -6
let spaceAttributes: [NSAttributedString.Key: Any] = [
.font: ThemeFont.splineRegular(size: 10),
.foregroundColor: ThemeColor.textBlack,
.paragraphStyle: paragraphStyle2
]
// Customized logic to assemble string components...
// Instance:
let titleText = NSAttributedString(string: "(obj.cityStateCountry ?? "")n", attributes: titleAttributes)
attributedString.append(titleText)
let addressText = NSAttributedString(string: "(shortAddress)n(coordinates)", attributes: otherAttributes)
attributedString.append(addressText)
// Date, identify, contact, and so on., with non-obligatory picture attachments
if obj.tempSetting.arrSelectedFields.incorporates(.ContactNumber) {
let icon = createImageAttachment(imageName: "iconCall", measurement: 14, yOffset: -4)
attributedString.append(icon)
}
// Extra strings appended equally...
return attributedString
}
Then I attempt to calculate the peak like this:
func getAttributedStringHeight(for attributedString: NSAttributedString, width: CGFloat) -> CGFloat {
let textStorage = NSTextStorage(attributedString: attributedString)
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(measurement: CGSize(width: width, top: .greatestFiniteMagnitude))
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = 0
textContainer.lineBreakMode = .byWordWrapping
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
_ = layoutManager.glyphRange(for: textContainer)
let top = layoutManager.usedRect(for: textContainer).top
return ceil(top)
}
However the returned top just isn’t completely correct. Typically the textual content will get minimize off or there’s additional area. I believe this is because of:
Customized fonts (ThemeFont.splineRegular/Daring)
Paragraph spacing (6 / -6 values)
Picture attachments (NSTextAttachment with icon photographs)
Presumably completely different baselines?