Get UIFont for content size category - ios

UIFont provides the +preferredFontForTextStyle: method to get a font instance with the proper size based on the user's selected content size category and the given UIFontTextStyle.
What I would like to do is get a font for a given text style and content size. Something like +fontForContentSizeCategory:andTextStyle:.
Unfortunately I cannot find anything similar to that in the headers for UIFont or UIFontDescriptor.
Any idea on how to achieve this?
Thanks

Unfortunately, both +[UIFont preferredFontForTextStyle:] and +[UIFontDescriptor preferredFontDescriptorWithTextStyle:] rely on -[UIApplication preferredContentSizeCategory] internally. They use a private function _CTFontDescriptorCreateWithTextStyle to retrieve a CoreText font descriptor with specific text style and size category, and that's eventually based on a category → size mapping from the configuration file CoreTextConfig.plist stored somewhere, but I assume you wouldn't want to use private APIs.
While hesitantly implying a possibility to dynamically swizzle -[UIApplication preferredContentSizeCategory] to trick +[UIFontDescriptor preferredFontDescriptorWithTextStyle:] into returning a font descriptor for the size class you want, I can't recommend any specific approach to this. You can retrieve a font descriptor like this:
let descriptor = UIFontDescriptor(fontAttributes: [ UIFontDescriptorTextStyleAttribute : UIFontTextStyleBody ])
but it won't contain a size attribute, so you would be left with trying to come up with a category → size mapping yourself.

Since iOS 10.0 this is possible using UITraitCollection:
let traitCollection = UITraitCollection(preferredContentSizeCategory: contentSizeCategory)
let font = UIFont.preferredFont(forTextStyle: textStyle, compatibleWith: traitCollection)

Related

JSPDF how to use variable fonts

I can happily use jspdf to add fonts to a pdf. For that so far I add a font for regular, one for italic, one for bold and one for bolditalic in my case.
Now I have some fonts that do not provide these different fonts but variable ttf-fonts and I struggle to use those with JSPDF.
So far my solution goes like this:
pdf.addFileToVFS(`${fontFamily}-bold.ttf`, fontBase64Data);
pdf.addFont(`${fontFamily.ttf}-bold.ttf, fontFamily, 'bold', 700);
where I read fontBase64 data from file (which works nicely for regaulr, italic etc) and do the same with the regular and italic fonts...
For variable fonts I tried to add a font with variable font weight with above code just use the fontBase64Data as I read it from the ttf file of variable font.
However that just leaves the font regular.
To my understanding that alos makes sense as the API of addFonts seems to associate a loaded font with a font weight it represents, but does not seem to apply a font weight to the font.
Since I want to use variable fonts however I seem to need to either
set a font as variable font, so weight would be automatically applied
apply a weight to the variable font via api and then define that as bold
So far I couldn't find any of that. Am I missing sth or are variable font weights currently not supported yet by jspdf?
Cheers
Tom

How to use font to write musical sheet

I am trying to make an iOS app that can make possible to write and edit musical sheet.
I was wondering how can I visualise it.
I did not found any complete framework in swift that can make it possible.
But I found this font bravura, but i did not found any example of use.
This is an OpenType Font.
Reading the documentation I should be able to decide through unicode characters, how to change the position of the next element.
But no it doesn't seem to work. At first I thought it was because of the ligatures as not all editors support it, I'm not a font expert and I could be wrong.
So I used the NSAttributedString class to modify these parameters. But the result is still not what is expected.
This is my code :
textView.font = UIFont(name: "Bravura-Text", size: 40)
let text = "\u{E014}\u{EB99}\u{E0A4} \u{E014}\u{EB91}\u{E0A4}"
let attributes = [
NSAttributedString.Key.font : UIFont(name: "Bravura-Text", size: 40)!,
NSAttributedString.Key.ligature : 2
] as [NSAttributedString.Key : Any]
let attributedString = NSAttributedString(string: text, attributes: attributes)
textView.attributedText = attributedString
E014 = Displaying a 5 line staff
EB99 = Lower by two staff positions
EB91 = Raise by two staff positions
E0A4 = The black notehead
This is the result :
result
Any suggestions to make it possible to use this font and its features on iOS?
I would like to write a musical sheet like this one.
Layout of music notation require higher-level layout rather than just displaying a line of text. (Analogous to Web pages using HTML as high-level layout rather than just lines of text.) Fonts can provide the basic symbols, and all of the basic symbols are encoded in Unicode. But you'll need some library that can read a music-notation markup language and layout the content.
You can probably find the kind of resources you'll need at https://www.w3.org/community/music-notation/

Getting a glyph boundingRect in draw#rect in UILabel

Using Swift, I want to get the boundingRect of a glyph, in draw#rect in a UILabel.
The UILabel already has a size (say 300x300 in the example) and qualities such as the text being centered.
class RNDLabel: UILabel {
override func draw(_ rect: CGRect) {
let manager = NSLayoutManager()
let store = NSTextStorage(attributedString: NSAttributedString(
string: text!,
attributes: [NSAttributedString.Key.font: font]))
store.addLayoutManager(manager)
let textContainer = NSTextContainer(size: rect.size)
// note, intrinsicContentSize is identical there, no difference
manager.addTextContainer(textContainer)
let glyphRange = manager.glyphRange(
forCharacterRange: NSRange(location: 0, length: 1),
actualCharacterRange: nil)
let glyphRect = manager.boundingRect(
forGlyphRange: glyphRange, in: textContainer)
print("glyphRect \(glyphRect)")
...context?.addRect(glyphRect), context?.drawPath(using: .stroke)
super.draw(rect)
}
The green square is not correct - it should be more like these red squares!
There seems to be a number of problems:
surely the layoutManager I make, should get the qualities of the UILabel, eg "centered text"? (I believe you can't actually directly access the layoutManager of a UILabel, though?)
should we be using something like CTLineGetOffsetForStringIndex? Is that even possible in draw#rect
notice as well as not having the correct offset, the green box seems the wrong height anyway. (It looks more like a plain old intrinsicContentSize rather than a glyph bounding box.)
How to?
For the record, my overall aim is to move the glyph around, based on the actual glyph box (which of course is different for "y", "X", etc). But in general there are many useful reasons to know the box of a glyph.
Your original question is sort of an unquestion, because it says two completely opposite things.
On the one hand, you say UILabel.
On the other hand, you use terms like NSLayoutManager and NSTextStorage and NSTextContainer — the TextKit stack.
Those are opposites because UILabel is not drawn with the TextKit stack. So what you're asking to do is like trying to lift a piece of paper with a magnet; magnets do lift things, but what they lift are magnetic materials, and paper is not one of those. To be sure, UILabel must draw in some deterministic way, but what that way is, is completely unknown and opaque and has nothing to do with TextKit.
On the other hand, UITextView, or a view that your draw yourself using TextKit, does use TextKit, and now all the TextKit tools apply. So what you're asking to do would be a lot more straightforward if this were a UITextView (or a view that you draw yourself using TextKit).
This need not change anything very much about the appearance of the interface. A UITextView can be made to act a lot like a UILabel (make it noneditable and nonscrollable) but with the important difference that the whole text kit stack is directly exposed. So that's where I'd start. I'm one of those people who prefers to use the framework rather than to fight it.
It turns out the answer to this question seems to be:
In fact, surprisingly or not, you basically have no access to glyph information in UILabel specifically.
So realistically you can't get those glyph "actual shapes" in UILabel.
In particular RobN. has pointed out that an investigation showed that in UILabel, _drawTextInRect:baselineCalculationOnly does the work and that is a big pile of ad hoc code.
A summary of the situation would seem to be that UILabel simply predates NSLayoutManager / Core Text and (as yet) just plain does not use those modern systems.
Only those modern systems give you this ...
... sort of access to glyph-by-glyph shapes.

Force UIFont to Render as Monospaced

Is it possible to force a UIFont to be monospaced?
Specifically I'm using a font which does not contain monospaced numbers (tabular numerals). Creating a modified font object which is monospaced and adding that font to the numeric segments of attributed strings would work great.
Another solution may be to add custom attributes to an attributed string and modify what is handling the layout of the text to use a fixed size for glyphs in particular ranges.
Things that Haven't Worked:
There are a number of questions that propose solving similar problems by overriding -drawRect: or -drawTextInRect: on a UILabel (see: Is it possible to alter the letter-spacing/kerning of a font with Cocoa Touch?). This seems like an insane solution and would be prohibitively complex if a string mixes monospaced and not-monospaced fonts.
There are also number of questions which suggest, specifically in regards to numerals, creating a font with a font descriptor with certain font features enabled. (see Displaying proportionally spaced numbers (instead of monospace / tabular) on iOS). This seems only to work in fonts which include these features. The font I'm using does not include these features and they have no effect. The font features can be checked by using something like NSLog(#"%#", CTFontCopyFeatures ( ( __bridge CTFontRef ) myFont ));

How do I get a bold version of UIFont's prefferedFontForTextStyle?

In iOS 7, users can manipulate their fonts from the control panel, something designed to help (amongst other things) visually impaired users.
I'm trying to work with the new paradign by using the new methods created to support that functionality. For the most part, it's easy enough -- just use [label setFont:[UIFont prefferedFontForTextStyle:UIFontTextStyleHeadline]] or whatever format you need.
But occasionally I need to adjust those. For example, maybe headline needs to be a bit bigger. I can use this answer to that. Unfortunately, I can't figure out how to apply that answer to other changes, such as simply bolding the font without changing the size.
You can try this:
UIFontDescriptor *descriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleHeadline];
/// Add the bold trait
descriptor = [descriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
/// Pass 0 to keep the same font size
UIFont *font = [UIFont fontWithDescriptor:descriptor size:0];

Resources