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"
Related
I am trying to specify the font family of every label in my iOS app in a way that makes it fairly easy to change them later. I don't want to have to go through Interface Builder and reset every font on every screen. According to this post, I have created a method that will find all the fonts in a view and set them accordingly.
In my case, there are a few different font families I need to use based on whether the font is bold, italic, or light (e.g. skinny). These are all located in separate files such as "OpenSans-Semibold.ttf", "OpenSans-Italic.ttf", and "OpenSans-Light.ttf".
Ideally, I would like to be able to set the font to bold, italic, or light in Interface Builder, then have the code override just the font family, using the appropriate .ttf file. According to this post, I can pretty easily detect whether the font has been set to bold or italic, but finding out whether it's light or not doesn't seem to be working.
For the light fonts, the value of "traits" is 0x0--so no flags are set. Is there another way to detect light fonts?
Code looks like this:
- (void) setFontFamily:(UIView*)view
{
if([view isKindOfClass:[UILabel class]])
{
UILabel* label = (UILabel*)view;
UIFontDescriptorSymbolicTraits traits = label.font.fontDescriptor.symbolicTraits;
BOOL bold = traits & UIFontDescriptorTraitBold;
BOOL italic = traits & UIFontDescriptorTraitItalic;
if(bold)
[label setFont:[UIFont fontWithName:#"OpenSans-Semibold"size:label.font.pointSize]];
else if(italic)
[label setFont:[UIFont fontWithName:#"OpenSans-Italic"size:label.font.pointSize]];
else if(light)
[label setFont:[UIFont fontWithName:#"OpenSans-Light"size:label.font.pointSize]];
else
[label setFont:[UIFont fontWithName:#"OpenSans"size:label.font.pointSize]];
}
for(UIView* subView in view.subviews)
[self setFontFamily:subView];
}
Your entire approach to determining a font based on its characteristics is problematic:
else if(italic)
[label setFont:
[UIFont fontWithName:#"OpenSans-Italic"size:label.font.pointSize]];
You are hard-coding the font name based on the trait. Instead, ask the runtime for the font based on the name and trait. In this very simple example I find out what installed font, if any, is an italic variant of Gill Sans:
UIFont* f = [UIFont fontWithName:#"GillSans" size:15];
CTFontRef font2 =
CTFontCreateCopyWithSymbolicTraits (
(__bridge CTFontRef)f, 0, nil,
kCTFontItalicTrait, kCTFontItalicTrait);
UIFont* f2 = CFBridgingRelease(font2);
Note that this code is valid in iOS 7 only, where CTFontRef and UIFont are toll-free bridged to one another. In theory it should be possible to do this without C functions through UIFontDescriptor, but the last time I looked it was buggy and didn't work for all fonts (e.g. Gill Sans!).
That is what you should be doing: determine the symbolic and weight traits of your starting font, and then ask the runtime for the font that most close matches your requirements.
I am creating UILabel, for the label i can set the font name as HelveticaNeue Regular, Light, UltraLight etc, But i unable to set the font name as HelveticaNeue Thin, it is not working as expected. I did like,
label.font = [UIFont fontWithName:#"HelveticaNeue-Thin" size:16];
Also i have searched on Google didnt got any solution. How to fix this issue? Thanks.
This font is bundled with iOS 7, so if you're targeting iOS 7 and above your
label.font = [UIFont fontWithName:#"HelveticaNeue-Thin" size:16.0f];
will work.
However if you are targeting iOS 6.1 and below you'll need to embed the font
Updated answer to support swift
let font = UIFont(name: "HelveticaNeue-Thin", size: 16.0)!
UIFontDescriptor *helveticaNeueFamily =
[UIFontDescriptor fontDescriptorWithFontAttributes:
#{ UIFontDescriptorFamilyAttribute: #"Helvetica Neue" }];
NSArray *matches =
[helveticaNeueFamily matchingFontDescriptorsWithMandatoryKeys: nil];
The matchingFontDescriptorsWithMandatoryKeys: method as shown returns an array of font descriptors for all the Helvetica Neue fonts on the system, such as HelveticaNeue, HelveticaNeue-Medium, HelveticaNeue-Light, HelveticaNeue-Thin, and so on.
You can modify the fonts returned by preferredFontForTextStyle: by applying symbolic traits, such as bold, italic, expanded, and condensed. You can use font descriptors to modify particular traits, as shown in Listing 9-2.
referenced by apple
or
this font you can't apply directly.
so you can customize your font
How to use custom fonts in iPhone SDK?
This has worked for me. Write this code below your label declarations.
It sets all the UILabel under a function with same font.
[[UILabel appearance]setFont:[UIFont fontWithName:#"HelveticaNeue-Thin" size:32.0f]];
To set font to particular UILabel use this code :
[labelName setFont:[UIFont fontWithName:#"HelveticaNeue-Thin" size:15.0f]];
Can anybody please explain how can we make any font family font, bold or unbold + Italic or Non Italic + Underlined or Non underLined. Everywhere I got the method that make the changes but on system font. I even tried giving 2 attributes to NSAttributed string
1. Bold
2. A font family from list of supported font family
But it didnt work. Thanks in Advance.
try this
UIFontDescriptor *fontDescriptor = [[UIFontDescriptor alloc] init];
UIFontDescriptor *fontDescriptorForHelveticaNeue = [fontDescriptor fontDescriptorWithFamily:#"Helvetica Neue"];
UIFontDescriptor *symbolicFontDescriptor = [fontDescriptorForHelveticaNeue fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
UIFontDescriptor *symbolicFontDescriptor1 = [fontDescriptorForHelveticaNeue fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitMonoSpace];
NSString *text = #"iOS 7";
if(some condition){
CGSize fontSize = [text sizeWithAttributes:#{NSFontAttributeName:[UIFont fontWithDescriptor:symbolicFontDescriptor size:17.0f]}];
}
else{
CGSize fontSize = [text sizeWithAttributes:#{NSFontAttributeName:[UIFont fontWithDescriptor:symbolicFontDescriptor1 size:17.0f]}];
}
You can't do it with a few lines of code. A normal font and its bold version are completely separated (ie they're like two unrelated fonts), and if you have a look at iosfonts, the naming is not consistent. Some fonts don't have bold version, and some have several bold versions!
A solution (that requires a bit of effort, but surely works): create a list of pairs of font names, like this
{"ArialHebrew", "ArialHebrew-Bold"},
{"AvenirNext-Regular", "AvenirNext-Bold"},
...
And populate the list of fonts with the regular version (the left one). If the user desires to make it bold, then switch to the bold version (the right one).
My recommendation is to limit the number of choices for user (as iOS always does): you don't need to copy the whole list from iosfonts! just some popular ones are enough.
This may not be sufficiently generic for your purses, but maybe it'll help someone else
+ (UIFont *)whateverInvertedBoldnessFontFromFont:(UIFont *)font pointSize:(CGFloat)pointSize
{
NSString *customFontFamilyName = #"Whatever";
NSString *ibFontName = font.fontName;
NSString *customFontStyle = nil;
if ([ibFontName rangeOfString:#"Bold"].location != NSNotFound) {
customFontStyle = #"Regular";
}
else {
customFontStyle = #"Bold";
}
UIFont *customFont = [UIFont fontWithName:[NSString stringWithFormat:#"%#-%#", customFontFamilyName, customFontStyle] size:pointSize];
return customFont;
}
unfortunately this is quite fragile and works reliably when the source and destination
font families are known
If you want to set it programmatically, you must check with the font supported by xCode (iOS).
and if you want to do bold to any font then you have to use :
UIFont* boldFont = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
[myLabel setFont:boldFont];
where myLabel is your label name.
I'm trying to figure out how to best bold and un-bold a UILabel with a font that was defined in the Interface Builder.
I know I can do this, for example:
[myLabel setFont:[UIFont boldSystemFontOfSize:14.0]];
But then I'm forcing the font to potentially different (both in style and size) than the way it was designed in IB.
I'm looking for something that essentially does this:
[myLabel setBold:TRUE];
or False, as the case may be.
Is there a way to do this?
Unfortunately, there's no real concept of "Bold" in UIKit. If you ever try setting part of an attributed string to "Bold", you are actually selecting the bold font variant in the same font family.
You could so something semihackish like this:
#implementation UIFont (BoldVariant)
- (UIFont *)boldVariant
{
for (NSString *fontName in [UIFont fontNamesForFamilyName:self.familyName]) {
if ([fontName hasSuffix:#"-Bold"]) {
return [UIFont fontWithName:fontName size:self.pointSize];
}
}
// If we couldn't find it, return the same font.
return self;
}
#end
This assumes that the font follows the standard naming scheme. It also assumes that fontNamesForFamilyName: returns any values. I noticed that with the system font, it returns an empty array.
If you are using for example system font which is Helvetica you can make the label.text bold like this:
myLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:14];
You can find iOS fonts for example in this site: link
You want an approach that works regardless of the font that is in place in your label, so it works with multiple labels?
How about this?
Fetch the current font from the label using it's font property.
Get the font family name for that font.
Ask the font family for it's list of fonts using the UI fontNamesForFamilyName.
See if you can find a bold font in the list of fonts you get back. If so, request that font at your current font size. If not, use the bold system font at the current size. (You might have to string parse the font names looking for the word "bold" in the name. Ugh.)
Not ideal, but you should be able to make it work.
I was able to find nice and clear solution:
extension UIFont {
/// Returns same font but with specific `symbolicTraits`.
func with(symbolicTraits: UIFontDescriptor.SymbolicTraits) -> UIFont {
let descriptor = fontDescriptor.withSymbolicTraits(symbolicTraits) ?? fontDescriptor
return UIFont(descriptor: descriptor, size: pointSize)
}
}
Usage:
label.font = label.font.with(symbolicTraits: .traitBold)
Or if you want to mix multiple traits:
label.font = label.font.with(symbolicTraits: [.traitBold, .traitItalic) // returns same font (name and size) but is bold and italic.
I have recently started using avenir as the font for my button text in my storyboard. It looks normal when I run it on ios6 , however in ios5 and lower as it doesn't support avenir it just uses the system default which looks awful aswell as the text not all fiting in the button, like so
Can anyone tell me how I would select a different font and text size for ios5, or a different font and text size when it returns nil to avenir?
UIFont *font = [UIFont fontWithName:#"iOS 6 font" size:SIZE];
if (!font) {
font = [UIFont fontWithName:#"Legacy font" size:SIZE];
}