I'm using dynamic type in an application and have scenarios where I want to change the font's appearance, for example making it italic or unbolding it. Adding a style is easy enough:
UIFontDescriptor *descriptor = [[UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleHeadline]
fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic];
UIFont *font = [UIFont fontWithDescriptor:descriptor size:descriptor.pointSize];
There's no clear mechanism for removing a style however. I could try adjusting the attributes but they look even more daunting, with completely undocumented API's:
Regular Headline: {
NSCTFontUIUsageAttribute = UICTFontTextStyleHeadline;
NSFontNameAttribute = ".AppleSystemUIHeadline";
NSFontSizeAttribute = 17;
}
Italic Headline: {
NSCTFontUIUsageAttribute = UICTFontTextStyleItalicHeadline;
NSFontNameAttribute = ".AppleSystemUIItalicHeadline";
NSFontSizeAttribute = 17;
}
Is there another avenue I'm missing? I could use [UIFont systemFontWithSize:descriptor.pointSize] but I don't want to lose whatever drawing rules are provided by dynamic type.
The fontDescriptorWithSymbolicTraits: method is actually capable of doing what you want, with the exception of some edge cases in font trait support among the built-in semantic text styles. The key concept here is that this method replaces all symbolic traits on the previous descriptor with the new trait(s). The documentation is a bit wishy-washy on this simply stating that the new traits "take precedence over" the old.
Bitwise operations are used to add and remove specific traits, but it appears that special care is required when working with a descriptor generated by preferredFontDescriptorWithTextStyle:. Not all fonts support all traits. The headline font, for instance, is weighted according to the user's preferred content size and even if you can strip the descriptor of its bold trait, the matching UIFont will be bold. Unfortunately, this is not documented anywhere so the discovery of any additional nuances is left as an exercise for the reader.
The following example illustrates these issues:
// Start with a system font, in this case the headline font
// bold: YES italic: NO
UIFontDescriptor * originalDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleHeadline];
NSLog(#"originalDescriptor bold: %d italic: %d",
isBold(originalDescriptor), isItalic(originalDescriptor));
// Try to set the italic trait. This may not be what you expected; the
// italic trait is not added. On a normal UIFontDescriptor the italic
// trait would have been set and the bold trait unset.
// Ultimately it seems that there is no variant of the headline font that
// is italic but not bold.
// bold: YES italic: NO
UIFontDescriptor * italicDescriptor = [originalDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic];
NSLog(#"italicDescriptor bold: %d italic: %d",
isBold(italicDescriptor), isItalic(italicDescriptor));
// The correct way to make this font descriptor italic (and coincidentally
// the safe way to make any other descriptor italic without discarding its
// other traits) would be as follows:
// bold: YES italic: YES
UIFontDescriptor * boldItalicDescriptor = [originalDescriptor fontDescriptorWithSymbolicTraits:(originalDescriptor.symbolicTraits | UIFontDescriptorTraitItalic)];
NSLog(#"boldItalicDescriptor bold: %d italic: %d",
isBold(boldItalicDescriptor), isItalic(boldItalicDescriptor));
// Your intention was to remove bold without affecting any other traits, which
// is also easy to do with bitwise logic.
// Using the originalDescriptor, remove bold by negating it then applying
// a logical AND to filter it out of the existing traits.
// bold: NO italic: NO
UIFontDescriptor * nonBoldDescriptor = [originalDescriptor fontDescriptorWithSymbolicTraits:(originalDescriptor.symbolicTraits & ~UIFontDescriptorTraitBold)];
NSLog(#"nonBoldDescriptor bold: %d italic: %d",
isBold(nonBoldDescriptor), isItalic(nonBoldDescriptor));
// Seems like it worked, EXCEPT there is no font that matches. Turns out
// there is no regular weight alternative for the headline style font.
// To confirm, test with UIFontDescriptorTraitsAttribute as the mandatory
// key and you'll get back a nil descriptor.
// bold: YES italic: NO
nonBoldDescriptor = [nonBoldDescriptor matchingFontDescriptorsWithMandatoryKeys:nil].firstObject;
NSLog(#"nonBoldDescriptor bold: %d italic: %d",
isBold(nonBoldDescriptor), isItalic(nonBoldDescriptor));
FYI, the isBold and isItalic functions used above for the sake of brevity could be implemented as follows:
BOOL isBold(UIFontDescriptor * fontDescriptor)
{
return (fontDescriptor.symbolicTraits & UIFontDescriptorTraitBold) != 0;
}
BOOL isItalic(UIFontDescriptor * fontDescriptor)
{
return (fontDescriptor.symbolicTraits & UIFontDescriptorTraitItalic) != 0;
}
Related
I have a custom font included in my Xcode 7, iOS 9 targeted project. I want to make the font monospaced. I tried this, and didn't work:
let originalFont = UIFont(name: "My Custom Font", size: 18)
let originalFontDescriptor = originalFont!.fontDescriptor()
let fontDescriptorFeatureSettings = [
[
UIFontFeatureTypeIdentifierKey: kNumberSpacingType,
UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector
]
]
let fontDescriptorAttributes = [UIFontDescriptorFeatureSettingsAttribute: fontDescriptorFeatureSettings]
let fontDescriptor = originalFontDescriptor.fontDescriptorByAddingAttributes(fontDescriptorAttributes)
let font = UIFont(descriptor: fontDescriptor, size: 0)
topLabel.font = font
With or without above code, the label displayed in proper custom font. It's just above code doesn't do anything.
My following answer is only making numbers (not the whole font) of an existing font monospaced (if the font supports it)
At least I was searching for making numbers monospaced when finding this Thread. So I hope it will help although it answers another question.
This works just fine, tested on Swift 5 and iOS14+13:
(As long as "your font is supporting the monospaced digits feature".)
extension UIFont {
var monospacedDigitFont: UIFont {
let oldFontDescriptor = fontDescriptor
let newFontDescriptor = oldFontDescriptor.monospacedDigitFontDescriptor
return UIFont(descriptor: newFontDescriptor, size: 0)
}
}
private extension UIFontDescriptor {
var monospacedDigitFontDescriptor: UIFontDescriptor {
let fontDescriptorFeatureSettings = [[UIFontDescriptor.FeatureKey.featureIdentifier: kNumberSpacingType, UIFontDescriptor.FeatureKey.typeIdentifier: kMonospacedNumbersSelector]]
let fontDescriptorAttributes = [UIFontDescriptor.AttributeName.featureSettings: fontDescriptorFeatureSettings]
let fontDescriptor = self.addingAttributes(fontDescriptorAttributes)
return fontDescriptor
}
}
Then you can use it on any label like this:
/// Label with monospacing activated
myLabel.font = myLabel.font.monospacedDigitFontDescriptor
/// Label with monospacing not activated (default is proportional spacing)
myLabel.font = myLabel.font
(source: https://blog.usejournal.com/proportional-vs-monospaced-numbers-when-to-use-which-one-in-order-to-avoid-wiggling-labels-e31b1c83e4d0)
The code you are using is not making font monospaced.
It's tweaking font to render digits in monospace mode. So all with this font digits will have same width.
Below is an example with 4 labels, 1 is using custom font Docis Light, 2nd is Docis Light with monospaced digits on, 3rd is system font of same size, 4th is system font with monospaced digits on:
As you see, this custom font already supports monospace digits feature out of the box with no tweak required.
If you need to use monospaced (not just digits) font, you have to use custom monospaced font (designed to be monospaced) or you can use built-in iOS monospaced fonts such as Courier or Menlo (See all available iOS fonts at http://iosfonts.com/)
This is how they look like with same scenario:
With or without tweaking, they are already monospaced and the digits are monospaced as well.
I answered similar question here, probably, I should just link the answer instead of images but it so much more visual.
Don't forget to import the header file. Hope it will work. This solution is in Objective-C
#import <CoreTextArcView.h>
UIFont *const existingFont = [UIFont preferredFontForTextStyle: UIFontTextStyleBody];
UIFontDescriptor *const existingDescriptor = [existingFont fontDescriptor];
NSDictionary *const fontAttributes = #{
UIFontFeatureTypeIdentifierKey
UIFontDescriptorFeatureSettingsAttribute: #[
#{
UIFontFeatureTypeIdentifierKey: #(kNumberSpacingType),
UIFontFeatureSelectorIdentifierKey: #(kMonospacedNumbersSelector)
}]
};
UIFontDescriptor *const monospacedDescriptor = [existingDescriptor fontDescriptorByAddingAttributes: fontAttributes];
UIFont *const proportionalFont = [UIFont fontWithDescriptor: monospacedDescriptor size: [existingFont pointSize]];
My app uses only system fonts, and I am creating them with function -
+ (UIFont * _Nonnull)systemFontOfSize:(CGFloat)fontSize weight:(CGFloat)weight
How Can I make System font Italic with weight UIFontWeightThin?
I cannot use the call for specific family font (fontWithName:) since I want it to be system fonts only.
Thanks :)
You should create Font Descriptor at first that contain the type of your font if it Italic or Bold or Thin, etc..
UIFontDescriptor* desc = [UIFontDescriptor fontDescriptorWithFontAttributes:
#{
UIFontDescriptorFaceAttribute: #"Thin"
}
];
after that create a font object that hold the descriptor information
UIFont *font = [UIFont fontWithDescriptor:desc size:17];
So, set you font object to your label.
Now you got a font object using system font but you can change the the type and size of it without using fontWithName.
What about something like this:
[youLabel setFont:[UIFont fontWithName:[youLabel.font fontName] size:UIFontWeightThin]];
Is there a way to set bold text using ObjectSetText() function in MQL4.
Should a font name be for example "Arial Bold" or can I set a path to the font .ttf-file?
If a path option is possible, is that path relative or absolute?
ObjectSetText() uses O/S-registered fonts & only limited controls
as one may test on GUI panels, MQL4 operations do not have full type-setting font-manipulation controls available via code
( this is all about trading, isn't it? )
Check what fonts are available from your O/S:
( or from used Docker/WINE thin-wrapper container )
So in MQL4 code there will thus simply be a string-typed or #define-ed literal specification of the font name and one may additionally set aFontSIZE + aFontCOLOUR attribute(s)
#define clrSignalLABEL clrAqua // LITERAL-way
#define iLabelFontSIZE 24
string signalTextFONT 'Times New Roman'; // STRING-way
input bool Font_Bold = true;
string FB;
int init()
{
if(Font_Bold == true)
{
FB = "Arial Bold";
}
else
{
FB = "Arial";
}
}
ObjectSetText("name", Text, FontSize, FB, FontColor);
I have a regular font in a label called _label and I' trying to make it bold and then only italic (so I want to remove the bold style)
To make it bold, I'm using the following code :
CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)_label.font.fontName, _label.font.pointSize, NULL);
CTFontRef boldFont = CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, kCTFontBoldTrait, kCTFontBoldTrait);
CFStringRef boldName = CTFontCopyFullName(boldFont);
_label.font = [UIFont fontWithName:(__bridge NSString *)boldName size:_label.font.pointSize];
This is working great. However when I'm trying to make it only italic, with the following code, the font ends up bold and italic:
font = CTFontCreateWithName((__bridge CFStringRef)_label.font.fontName, _label.font.pointSize, NULL);
boldFont = CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, kCTFontBoldTrait | kCTFontItalicTrait, kCTFontItalicTrait); // I also tried 'kCTFontItalicTrait, kCTFontItalicTrait' for the last two parameters
boldName = CTFontCopyFullName(boldFont);
_label.font = [UIFont fontWithName:(__bridge NSString *)boldName size:_label.font.pointSize];
Obviously I'm not using CTFontCreateCopyWithSymbolicTraits correctly. How to remove the bold style?
You should use:
boldFont = CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, kCTFontItalicTrait, kCTFontBoldTrait | kCTFontItalicTrait);
(although you might want to change your variable name).
The symTraitMask parameter (the last one) indicates which bits of the trait mask should be affected by the call. You want to affect both the "bold" and "italic" bits.
The symTraitValue parameter (second to last) indicates the new values for the affected bits. You want those bits to be changed to have "italic" but not have "bold".
I want to resize the font-size in some UITextViews. That works fine with an outlet collection and this code:
for (UITextView *view in self.viewsToResize) {
if ([view respondsToSelector:#selector(setFont:)]) {
[view setFont:[UIFont systemFontOfSize:view.font.pointSize + 5]];
}
}
But my problem is, that not every textView uses the systemFont in normal weight, some of them are in bold weight. Is it possible to get the font-weight? With a po view.font in the debug area I can see everything I need:
$11 = 0x0c596ea0 <UICFFont: 0xc596ea0> font-family: "Helvetica"; font-weight: normal; font-style: normal; font-size: 12px
But how can I access the font-weight?
Using a second outlet collection for the bold views could solve my problem. But I'm wondering that I found nothing to get only the font-weight.
I have figured out how to get the font weights, you have to spelunk down to Core Text:
let ctFont = font as CTFont
let traits = CTFontCopyTraits(ctFont)
let dict = traits as Dictionary
if let weightNumber = dict[kCTFontWeightTrait] as? NSNumber {
print(weightNumber.doubleValue)
}
Enjoy!
UIFont does not have a bold/italic/... property, so you will have to rely on the font name only.
This will be a problem if you don't know which fonts will be used.
In the case you know that you will use eg. only Helvetica you can try this:
UIFont *font = textview.font;
if([font.fontName isEqualToString:#"Helvetica-Bold"])
NSLog(#"It's Bold!");
Alternatively you can search font.fontName for the word "bold"/"medium"/"light" etc., but that's not a guarantee you will get something from every available font:
if ([font.fontName rangeOfString:#"bold" options:NSCaseInsensitiveSearch].location == NSNotFound) {
NSLog(#"font is not bold");
} else {
NSLog(#"font is bold!");
}
// if font.fontName contains "medium"....
// if font.fontName contains "italic"....
Check http://iosfonts.com/ for the available font names.
But my problem is, that not every textView uses the systemFont in
normal weight, some of them are in bold weight.
If you want to use Bold System Font then you can simply use
[UIFont boldSystemFontOfSize:15.0];
However, I am still thinking of that special case in which you need to use font-weight.
Update :
There is nothing in the UIFont Class using which you can get font-weight directly. You can take a look at UIFont Class Reference.
Only thing that you can do is to get the font-name and try to find out the "bold" sub-string in the font name. If any match found that means font-weight of that specific font is "bold".
But, still this is not the most efficient method.
You can get a UIFontDescriptor for a font using the fontDescriptor method. Then you get the fontAttributes dictionary of the UIFontDescriptor, get the UIFontDescriptorTraitsAttribute from the dictionary which returns another dictionary, then read the UIFontWeightTrait from that dictionary. Not tested.
Now it's tested: Doesn't work. fontAttributes always returns a dictionary with two keys for font name and font size, and that's it. I suppose "this doesn't work" is also an answer when something should work according to the documentation...
You can try symbolicTraits, but that's not useful either: It returns "bold" only if the whole font family is bold.