How to change iOS system font dynamically but remember original font? - ios

I am able to change the language of my iOS app on the fly without terminating the app. However, I want to change the system fonts on the fly too because the standard Helvetica Neue fonts don't look good with some languages. I'm going to use a category from this SO answer and include it in my .pch:
#implementation UIFont (SytemFontOverride)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize {
return [UIFont fontWithName:#"FONT NAME" size:fontSize];
}
#pragma clang diagnostic pop
#end
However, when in English I want to use the default system fonts which vary slightly from iOS version and device. My question is how can I achieve something like this
static UIFont *defaultRegularFont = [UIFont systemFontOfSize:12];
so I can reuse it when the app switches back to English like this
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize {
...
// If English
return [UIFont fontWithName:[defaultRegularFont fontName] size:fontSize];
}

Related

San Francisco font: bold + italic?

In the past, if I wanted to use bold and italic on the same text, I'd select a font by name, like this:
font = [UIFont fontWithName:#"HelveticaNeue-BoldItalic" size:size];
Now I'm trying to do this with the current iOS system font, San Francisco. This answer says it's not safe to refer to this font by name, and indeed, when I try it, some font-related methods do nothing and some crash the app.
Of course there is a boldSystemFontOfSize and italicSystemFontOfSize method, but no boldItalicSystemFontOfSize method.
Does that leave any other way to use bold+italic with the San Francisco font?
Here's a category based on the answer suggested by #rmaddy:
#interface UIFont (UIFontBoldItalic)
+ (UIFont *)boldItalicSystemFontOfSize:(CGFloat)fontSize;
#end
#implementation UIFont (UIFontBoldItalic)
+ (UIFont *)boldItalicSystemFontOfSize:(CGFloat)fontSize {
UIFontDescriptor *fontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
uint32_t existingTraitsWithNewTrait = [fontDescriptor symbolicTraits] | UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic;
UIFontDescriptor *updatedFontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits:existingTraitsWithNewTrait];
UIFont *font = [UIFont fontWithDescriptor:updatedFontDescriptor size:fontSize];
return font;
}
#end
Although this doesn't specify "system font" or "San Francisco" anywhere, I assume the UIFontTextStyleBody will return the system font.

How to use bold, regular and italic font styles for custom fonts?

I am currently using the font Yoxall in my app, and have .ttf files for "Regular", "Bold", and "Italic". I am currently using the coke [UIFont fontWithName:#"Yoxall" size:20.0f] to set the font as the regular Yoxall, using the YOXALL__.ttf file in my supporting files. I would also like to use italic Yoxall elsewhere in my app, but I obviously cannot call the same method, as "Yoxall" refers to both these files.
What code would I use to distinguish between the regular, bold, and italic styles of this font?
Use +[UIFont familyNames] to list of all font family names known
to the system, you can use +[UIFont fontNamesForFamilyName:] to list
all of the font names known to the system.
Example code:
static void dumpAllFonts() {
for (NSString *familyName in [UIFont familyNames]) {
for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) {
NSLog(#"%#", fontName);
}
}
}
in output you can get font name. hope it's help
for (NSString *familyName in [UIFont familyNames]) {
for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName]){
NSLog(#"%#", fontName);
}
}
This function will give all fonts name.

Possible to detect Bold Text setting in Settings > Accessibility?

With iOS 7, it's possible to code your app to respect the user's setting for Dynamic Type - larger or smaller font sizes. You use the method preferredFontForTextStyle: and then listen to notifications in order to update the UI if the user changes the setting while your app is running. I am wondering if it's possible to do the same thing with the accessibility option "Bold Text" found in Settings > Accessibility. I realized that the Bold Text option actually requires you to restart the device, so there should be no need to listen to notifications because your app will be killed and relaunched anyways.
This is what I ultimately want to accomplish: I would like to change the navigation bar title text to a lighter style font. It may not be the default System font - it could be any font iOS can display, but I'll probably use HelveticaNeue-Light. I would also like to respect the user's preference for Bold Text. If it's enabled, I want to change the title text to a heavier weight of that same font - just like iOS does by default even though the default is already quite heavy - Helvetica Neue Medium. Indeed it does make it a little bit heavier when enabled. I want to do the same with a different font.
Here's what I'm doing to change it, but this obviously will be fixed no matter what the bold setting is:
[self.navigationController.navigationBar setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys: [UIFont fontWithName:#"HelveticaNeue-Light" size:17], [NSFontAttributeName, nil]];
I may have a solution but it seems to be a bad approach. I'm making a new font with a fixed size from the preferredFont for subheadline. This does almost exactly what I want - it automatically takes care of font-weight based on the Bold Text setting (HelveticaNeueRegular [I actually want Light] when disabled, HelveticaNeueMedium when enabled), but won't work for a different typeface. Perhaps there is a better approach?
UIFont *subtitleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
UIFont *titleFont = [subtitleFont fontWithSize:17];
[self.navigationController.navigationBar setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:titleFont, NSFontAttributeName, nil]];
As of iOS 8, it is possible to detect whether the user has enabled Bold Text in Settings using UIAccessibility.isBoldTextEnabled (docs) and UIAccessibility.boldTextStatusDidChangeNotification (docs).
For apps that also require iOS 7 support, I’ve written an elegant one-liner that works on iOS 7 & 8 with Helvetica Neue and even on iOS 9 with the San Francisco typeface, based on the fact that standard-weight fonts are commonly referred to as the “Regular” weight, and that body text uses this weight for readability:
Objective-C:
BOOL hasBoldText = ![[UIFont preferredFontForTextStyle:UIFontTextStyleBody].fontName hasSuffix:#"-Regular"];
Swift:
let hasBoldText = !UIFont.preferredFontForTextStyle(UIFontTextStyleBody).fontName.hasSuffix("-Regular")
You can use UIFontDescriptor for that:
UIFontDescriptor *fontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleSubheadline];
UIFont *font = [UIFont fontWithDescriptor:fontDescriptor size:17]; // better to use a constant
If you want to change when the font size changes, you can observe the UIApplicationContentSizeDidChangeNotification. I'm not sure if the Bold Text setting also sends this notification, but you can always update on applicationWillEnterForeground:. 99% of the time you update unnecessarily that way, but it should work if the user does decide to change it.
I found another solution. Just parse the current title font to see if it contains the substring 'bold' and if it does not find it, then you know Bold Text is disabled, and you can apply your custom font. Note that this would stop working if Apple changed the heading weight. For example, took it down one notch to Regular and Medium instead of Medium and Bold. And if Apple changes the font family, your fixed font won't match it obviously. But it doesn't seem to be a terrible solution.
UIFont *currentTitleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
//if Bold Text is disabled
if ([currentTitleFont.fontName rangeOfString:#"bold" options:NSCaseInsensitiveSearch].location == NSNotFound) {
UIFont *titleFont = [UIFont fontWithName:#"HelveticaNeue-Light" size:17];
[self.navigationController.navigationBar setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:titleFont, NSFontAttributeName, nil]];
}
else {
//put custom font here for when Bold Text is enabled, or do nothing to get the default
}
In iOS 7 and up, I noticed that the UIFontTextStyleHeadline is: HelveticaNeueInterface-Heavy.
I modified the op's response as follows:
UIFont *currentTitleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
//if Bold Text is disabled
if ([currentTitleFont.fontName rangeOfString:#"bold" options:NSCaseInsensitiveSearch].location == NSNotFound && [currentTitleFont.fontName rangeOfString:#"heavy" options:NSCaseInsensitiveSearch].location == NSNotFound) {
UIFont *titleFont = [UIFont fontWithName:#"HelveticaNeue-Light" size:17];
[self.navigationController.navigationBar setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys:titleFont, NSFontAttributeName, nil]];
}
else {
//put custom font here for when Bold Text is enabled, or do nothing to get the default
}
Try this one. It works for me.
let hasBoldText = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body).fontName.contains("bold")
UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body).fontName
11.4 12.0
".SFUIText"
".SFUIText-Semibold"
13.3

".SFUI-Regular"

".SFUI-Semibold"

Is there a way to change default font for your application

As I understand all standard controls use system font by default.
Also, API [UIFont systemFontOfSize: ] uses system font too.
Is there a way to redefine it for the whole application, instead of setting a font for table, labels and so on?
The answer is no, you cant change apple's systemFont, you need to set the font on your control yourself.
For best way to set a default font for whole iOS app, please check the below SO questions:
Set a default font for whole iOS app?
How to set a custom font for entire iOS app without specifying size
How do I set a custom font for the whole application?
Is there a simple way to set a default font for the whole app?
Define and export (by including a header in files or in precompiled header) a category of UIFont as following:
#implementation UIFont (Utils)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+ (UIFont *)systemFontOfSize:(CGFloat)size
{
return [UIFont fontWithName:#"YOUR_TRUETYPE_FONT_NAME_HERE" size:size];
}
+ (UIFont *)lightSystemFontOfSize:(CGFloat)size
{
return [UIFont fontWithName:#"YOUR_TRUETYPE_FONT_NAME_HERE" size:size];
}
+ (UIFont *)boldSystemFontOfSize:(CGFloat)size
{
return [UIFont fontWithName:#"YOUR_TRUETYPE_FONT_NAME_HERE" size:size];
}
+ (UIFont *)preferredFontForTextStyle:(NSString *)style
{
if ([style isEqualToString:UIFontTextStyleBody])
return [UIFont systemFontOfSize:17];
if ([style isEqualToString:UIFontTextStyleHeadline])
return [UIFont boldSystemFontOfSize:17];
if ([style isEqualToString:UIFontTextStyleSubheadline])
return [UIFont systemFontOfSize:15];
if ([style isEqualToString:UIFontTextStyleFootnote])
return [UIFont systemFontOfSize:13];
if ([style isEqualToString:UIFontTextStyleCaption1])
return [UIFont systemFontOfSize:12];
if ([style isEqualToString:UIFontTextStyleCaption2])
return [UIFont systemFontOfSize:11];
return [UIFont systemFontOfSize:17];
}
#pragma clang diagnostic pop
#end
Light variant comes as a useful extra starting with iOS 7. Enjoy! ;)

Interface builder is defaulting to Helvetica just now

I have been using a specific font which I've been testing on the iPad directly and it was working fine.
Now all of a sudden, the label or textview using the font are default back to Helvetica.
As a hack I'm setting the font manually, but this is ridiculous
self.taskNameView.font = [UIFont fontWithName:#"BradleyHandITCTT-Bold" size:24.0];
Any idea why all of a sudden, interface builder is freaking out?
I've tried cleaning but that didn't help.
I'm on XCode 4 and working on iOS 4.3
If you just want to override all fonts in your application, maybe a category on UIFont will do the trick?
Try adding this to e.g. your AppDelegate.m:
#implementation UIFont (FontOverride)
+(UIFont*) systemFontOfSize:(CGFloat)fontSize
{
return [UIFont fontWithName:#"radleyHandITCTT-Normal" size:fontSize];
}
+(UIFont*) boldSystemFontOfSize:(CGFloat)fontSize
{
return [UIFont fontWithName:#"radleyHandITCTT-Bold" size:fontSize];
}
+(UIFont*) italicSystemFontOfSize:(CGFloat)fontSize
{
return [UIFont fontWithName:#"radleyHandITCTT-Italic" size:fontSize];
}
#end

Resources