Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIFont: How to use Stylistic Alternate character?

In my App I want to use stylistic alternate font for 'a' and not system font.

Attaching screenshot which explains the different rendering of the font.

enter image description here

How can I enable this behaviour for UILabel and UITextView so that it renders the correct One Storey 'a'?

I did find a YouTube video link which explains exactly this but he is using a custom font and it is hardcoded. I want to use system font only but with this alternate character.

I might be able to hardcode UILabel with the custom character, I am not sure because I want to use System font. I don't want to use custom Font. What about UITextView which is editable? How can we make it use alternate a as and when the user types?

like image 772
FE_Tech Avatar asked Dec 24 '19 06:12

FE_Tech


1 Answers

This is a font feature called "Alternative Stylistic Sets" that you can configure with CoreText. Remember that not all fonts have this option, but the system fonts do. You need to figure out which alternative set you want, however.

First, create the font you're interested in:

import CoreText
import UIKit

let baseFont = UIFont.systemFont(ofSize: 72)

Then print out its features:

print(CTFontCopyFeatures(baseFont)!)

Find the section on Alternative Stylistic Sets, and specifically the set you want, "One storey a:"

    {
    CTFeatureTypeIdentifier = 35;
    CTFeatureTypeName = "Alternative Stylistic Sets";
    CTFeatureTypeSelectors =         (
                    {
            CTFeatureSelectorIdentifier = 2;
            CTFeatureSelectorName = "Straight-sided six and nine";
        },
                    {
            CTFeatureSelectorIdentifier = 4;
            CTFeatureSelectorName = "Open four";
        },
                    {
            CTFeatureSelectorIdentifier = 6;
            CTFeatureSelectorName = "Vertically centered colon";
        },
                    {
            CTFeatureSelectorIdentifier = 10;
            CTFeatureSelectorName = "Vertically compact forms";
        },
                    {
            CTFeatureSelectorIdentifier = 12;
            CTFeatureSelectorName = "High legibility";
        },
                    {
            CTFeatureSelectorIdentifier = 14;
            CTFeatureSelectorName = "One storey a";
        },
        ...

The important number is the selector (CTFeatureSelectorIdentifier), 14. With that you can create a new font descriptor and new font:

let descriptor = CTFontDescriptorCreateCopyWithFeature(
    baseFont.fontDescriptor,
    kStylisticAlternativesType as CFNumber,
    14 as CFNumber)

Or you can do this directly in UIKit if it's more convenient:

let settings: [UIFontDescriptor.FeatureKey: Int] = [
    .featureIdentifier: kStylisticAlternativesType,
    .typeIdentifier: 14
]

let descriptor = baseFont.fontDescriptor.addingAttributes([.featureSettings: [settings]])

(Note the somewhat surprising fact that .featureIdentifier is "CTFeatureTypeIdentifier" and .typeIdentifier is "CTFeatureSelectorIdentifier".)

And then you can create a new font (a zero size means to leave the size the same):

let font = UIFont(descriptor: descriptor, size: 0)

You can use that anywhere that accepts a UIFont.

like image 182
Rob Napier Avatar answered Oct 01 '22 13:10

Rob Napier