How to add padding to a NSMutableAttributedString?
Asked Answered
W

2

9

I have a label that uses a NSMutableAttributedString to write out the text as:

enter image description here

What I want to do is lower the asterisk's top padding so that its midY is even with the word Cuisine like below:

enter image description here

How can I add padding using a NSMutableAttributedString?

I know I can create a separate label with the asterisk alone and use anchors w/ a constant to center it but I want to see how this is possible using a NSMutableAttributedString

let cuisineLabel: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    
    let attributedText = NSMutableAttributedString(string: "Cuisine ", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17), NSAttributedStringKey.foregroundColor: UIColor.lightGray])
    
    attributedText.append(NSAttributedString(string: "*", attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 24), NSAttributedStringKey.foregroundColor: UIColor.red]))
    
    label.attributedText = attributedText
    
    return label
}()
Winburn answered 14/9, 2018 at 16:38 Comment(3)
Use the baselineOffset attribute. developer.apple.com/documentation/foundation/nsattributedstring/…Alphanumeric
@Code Different thanks it workedWinburn
You could use one of the many other asterisk characters such as ⁎, ∗, ✱, ✲, ❋, *, etc.Inquisitive
J
6

The baselineOffset attribute key is used for this purpose.

let cuisine = NSMutableAttributedString(string: "Cuisine")
let asterisk = NSAttributedString(string: "*", attributes: [.baselineOffset: -3])
cuisine.append(asterisk)

enter image description here

Obviously, you will have to calculate the offset using the font size of the rest of the text. This is why I believe that using a full width asterisk (*) is easier.

Result with full width asterisk (you might want its font size to be a proportion of the font size of the rest of the string):

enter image description here

Jennifer answered 14/9, 2018 at 16:49 Comment(5)
what is a full width asterisk?Winburn
@LanceSamaria It's code point U+FF0A: fileformat.info/info/unicode/char/ff0a/index.htmJennifer
@Jennifer Is there any way to calculate the offset using the font size ?Anabal
Try breaking down the problem. To calculate the offset, you need to know how high the asterisk and how high the rest of the text is, which you can get with size(withAttributes:). @MiteshDobareeyaJennifer
@Jennifer I am using $ sing. Is there any other way to set the $ into the center? I found the high of $ and the rest of the text but it won't help to set into the center. I divided the remaining space but the $ going too much up.Anabal
S
5

As Code Different points out, you can do this with baselineOffset attribute. A value of -8 should work for your case:

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        self.view = view

        let cuisineLabel: UILabel = {
            let label = UILabel()
            label.translatesAutoresizingMaskIntoConstraints = false
            label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
            let attributedText = NSMutableAttributedString(string: "Cuisine ", attributes: [
                NSAttributedStringKey.font: UIFont.systemFont(ofSize: 17),
                NSAttributedStringKey.foregroundColor: UIColor.lightGray])

            attributedText.append(NSAttributedString(string: "*", attributes: [
                NSAttributedStringKey.font: UIFont.systemFont(ofSize: 24),
                NSAttributedStringKey.baselineOffset: -8,
                NSAttributedStringKey.foregroundColor: UIColor.red]))

            label.attributedText = attributedText

            return label
        }()

        view.addSubview(cuisineLabel)

    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

If you're struggling with line height offsets being messed up because of the new baseline and you're using a multi-line label, try playing with lineHeightMultiple:

let lineStyle = NSParagraphStyle()
lineStyle.lineHeightMultiple = 0.8

...

NSAttributedStringKey.paragraphStyle = style

If not (and you're using multiple labels stacked on top of one another) then you probably just need to adjust the frame of each label in the series to compensate.

Stubbed answered 14/9, 2018 at 16:49 Comment(3)
I used Sweeper and rmaddy suggestions of using a different size asterisk with unicode character to keep the size at 17. Thanks for the help. Btw I upvoted you.Winburn
The only issue that I encountered was when attempting to set lineHeightMultiple. let lineStyle = NSParagraphStyle() should be let lineStyle = NSMutableParagraphStyle().Angleworm
Good catch, @NickKohrnStubbed

© 2022 - 2024 — McMap. All rights reserved.