47

I'm confused on how to use SF Symbols in text in an iOS project. I have a UIButton that uses a symbol just fine using UIImage systemImageNamed:. I would like to display a message about that button with some text in another view. I thought I should be able to use the Unicode reference to that symbol, but it doesn't render. My understanding is that these symbols are in the Private Use Area, but I cannot get them to render using code like @"Press the \U0010057C button."

I have tried importing the SFSymbolsFallback.ttf font file into my project.

I would expect to see the symbol rendered, but I get a ? instead.

Gene McCulley
  • 1,097
  • 1
  • 10
  • 15

4 Answers4

91

This works for me:

let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(systemName: "checkmark.circle")

// If you want to enable Color in the SF Symbols.
imageAttachment.image = UIImage(systemName: "checkmark.circle")?.withTintColor(.blue)

let fullString = NSMutableAttributedString(string: "Press the ")
fullString.append(NSAttributedString(attachment: imageAttachment))
fullString.append(NSAttributedString(string: " button"))
label.attributedText = fullString

Result:

enter image description here

Michcio
  • 2,708
  • 19
  • 26
  • I was thinking something like that should work, but using that in a UITextField embedded in a UIAlertController does not render the character. – Gene McCulley Oct 11 '19 at 12:33
  • Ah. I discovered that it doesn't render in the alert's `UITextField`, but does if I add a `UILabel`. – Gene McCulley Oct 11 '19 at 12:44
  • 9
    I might be able to make this work, but I would still like to understand how to use SF Symbol as a font without using `UIImage`. I'm confused on why there are code points assigned at all if these cannot be used in normal text. – Gene McCulley Oct 11 '19 at 12:47
12

I have been struggling with this same problem of how to use SF Symbol glyphs using the CoreText rendering APIs. On MacOS, the "SF Pro Text" font has 7500+ glyphs in it including the SF Symbol glyphs. On iOS, the system font only has ~2800 glyphs and don't seem to include the new SF Symbol glyphs. Beyond including the font in the project itself (which is against Apple's licensing I believe), I have not found a way to render these glyphs using their Unicode character values.

Werner Sharp
  • 301
  • 1
  • 2
  • 7
1

In macOS 13 Ventura you can simply copy-paste the symbols from the SF Symbols app into an NSString in Xcode, and it works great!

I also tested this under macOS 11 Big Sur. At first it didn't work, but then after I installed the SF Symbols app it started working.

So maybe this only works if the SF Symbols app is installed? I'm not sure.

Edit: It doesn't seem to be about the SF Symbols app but instead about the Fonts you have installed. You need to install certain fonts. SF Pro or something, in order for the SF Symbols to work in text.

Noah Nuebling
  • 219
  • 2
  • 11
  • 4
    This does not work in iOS 16 using 'System' font. The pasted symbols appear correct in the Strings in code, but when displayed in a UILabel, the symbols are rendered as a small square with an internal question mark (unknown glyph) – BlueskyMed Feb 07 '23 at 13:19
  • 2
    @BlueskyMed yes it's the same under macOS until you install the SFSymbols app. Maybe there's a way to ship the font with the app or something like that so it works under iOS too? – Noah Nuebling Feb 09 '23 at 13:56
1

For iOS this snippet can safe you a little bit of time:

extension NSAttributedString {

    static func create(
        blocks: [Block],
        font: UIFont? = nil,
        textColor: UIColor? = nil,
        symbolColor: UIColor? = nil
    ) -> NSAttributedString {

        let font = font ?? .preferredFont(forTextStyle: .body)
        let textColor = textColor ?? .label
        let symbolColor = symbolColor ?? textColor

        let attributedBlocks: [NSAttributedString] = blocks.map { block in
            switch block {
            case .text(let text):
                return NSAttributedString(
                    string: text,
                    attributes: [
                        .font: font,
                        .foregroundColor: textColor
                    ]
                )
            case .symbol(let imageName):
                let attachment = NSTextAttachment()
                let imageConfiguration = UIImage.SymbolConfiguration(font: font)
                attachment.image = UIImage(
                    systemName: imageName,
                    withConfiguration: imageConfiguration
                )?.withTintColor(symbolColor)
                return NSAttributedString(attachment: attachment)
            }
        }
        let string = NSMutableAttributedString(string: "")
        attributedBlocks.forEach {
            string.append($0)
        }
        return string
    }
    
    enum Block {
        case text(String)
        case symbol(String)
    }
}

You might want to decorate your strings with \t,\n or separators of your choice.

nayooti
  • 395
  • 2
  • 15