How do I generate a filtered set of available font family names? (like in Pages or TextEdit)

804 views Asked by At

I want to make a popup button like the one in Pages.app (or in TextEdit.app) whose menu is a filtered list of font families.

I can get an array of available font family names from [NSFontManager availableFontFamilies], but this provides far more font families than are in Pages's popup menu.

On the other hand, I can get what seems to be the correctly filtered set of font descriptors from [NSFontCollection fontCollectionWithName:NSFontCollectionUser], but that includes each member of the family as well (italic, bold, etc). I don't want to include each member in my popup, only the family names.

I want the filtered set of family names.

The names I get out of the NSFontManager seem sanitized for UI, whereas the name values I get out of font descriptor's attributes dictionary ([myFontDescriptor fontAttributes][NSFontNameAttribute]) are not. So I can't just make a simple set intersection of the two groups based on the string values, the same things might have different names.

2

There are 2 answers

1
Ken Thomases On BEST ANSWER

You can use -[NSFontDescriptor objectForKey:] to retrieve attributes not present in the -fontAttributes dictionary. If you use the attribute key NSFontFamilyAttribute, that gives you the font family name. Applying that to each font descriptor in [NSFontCollection fontCollectionWithName:NSFontCollectionUser] should give you what you need.

1
jiminybob99 On
    let collection = NSFontCollection(name: "Fixed Width")
    var names = [String]()
    for description in (collection?.matchingDescriptors)!{
        let name = description.fontAttributes[NSFontNameAttribute] as! String
        names.append(name)

    }
    print(names)

here is my code to save someone some time

Swiftlier

let collection = NSFontCollection(name: NSFontCollection.Name(rawValue: "Fixed Width"))
let names = collection?.matchingDescriptors?.compactMap { $0.fontAttributes[.name] as? String }

Assuming names isn't nil, you can unique them (as you should) by creating a set with them via Set(names).