Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertically aligning NSTextAttachment in NSMutableAttributedString

I'm adding an icon to a UILabel using NSTextAttachment inside an NSMutableAttributedString like this:

//Setting up icon
let moneyIcon = NSTextAttachment()
moneyIcon.image = UIImage(named: "MoneyIcon")
let moneyIconString = NSAttributedString(attachment: moneyIcon)

//Setting up text
let balanceString = NSMutableAttributedString(string: " 1,702,200")
balanceString.insert(moneyIconString, at: 0)

//Adding string to label
self.attributedText = balanceString
self.sizeToFit()

But for some reason the icon isn't vertically aligned

Does anybody know how can I align it?

Thank you!

like image 967
FS.O6 Avatar asked Dec 16 '17 10:12

FS.O6


2 Answers

use bounds property of NSTextAttachment.

//Setting up icon
let moneyIcon = NSTextAttachment()
moneyIcon.image = UIImage(named: "MoneyIcon")

let imageSize = moneyIcon.image!.size
moneyIcon.bounds = CGRect(x: CGFloat(0), y: (font.capHeight - imageSize.height) / 2, width: imageSize.width, height: imageSize.height)

let moneyIconString = NSAttributedString(attachment: moneyIcon)

//Setting up text
let balanceString = NSMutableAttributedString(string: " 1,702,200")
balanceString.insert(moneyIconString, at: 0)

//Adding string to label
self.attributedText = balanceString
self.sizeToFit()
like image 80
Warif Akhand Rishi Avatar answered Nov 25 '22 06:11

Warif Akhand Rishi


This answer, which is about vertically centering two differently sized fonts in a single NSAttributedString, mentions using the baseline offset to calculate the center of the string.

You can use the same approach when using an image:

  1. Subtract the font size from the image's height and divide it by 2.

  2. Subtract the font's descender from the value (since font size isn't the same as the ascent of your font). The font that you are particularly using (Baloo-Regular) has a descender value that differs from the standard and it should be divided by 2. Other fonts (including San Fransisco) don't need that fix or require a different divisor.

This code covers most cases, if your font behaves differently, you should check out the guide for managing texts in Text Kit.

// *Setting up icon*

let moneyIcon = NSTextAttachment()

// If you're sure a value is not and will never be nil, you can use "!".
// Otherwise, avoid it.

let moneyImage = UIImage(named: "MoneyIcon")!

moneyIcon.image = moneyImage
let moneyIconString = NSAttributedString(attachment: moneyIcon)

// *Setting up NSAttributedString attributes*

let balanceFontSize: CGFloat = 16

let balanceFont = UIFont(name: "Baloo", size: balanceFontSize)!

let balanceBaselineOffset: CGFloat = {
    let dividend =  moneyImage.size.height - balanceFontSize

    return dividend / 2 - balanceFont.descender / 2
}()

let balanceAttr: [NSAttributedString.Key: Any] = [
    .font: balanceFont,
    .baselineOffset: balanceBaselineOffset
]

// *Setting up text*

let balanceString = NSMutableAttributedString(
    string: " 1,702,200",
    attributes: balanceAttr
)

balanceString.insert(moneyIconString, at: 0)
like image 45
Tamás Sengel Avatar answered Nov 25 '22 06:11

Tamás Sengel