I have a date countdown in my app in which I'd like to make use of San Francisco's monospaced number feature. I currently retrieve the font using this code:
UIFontDescriptor *countdownFontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
NSArray *additionalFontSettings = #[#{UIFontFeatureTypeIdentifierKey: #(kNumberSpacingType), UIFontFeatureSelectorIdentifierKey: #(kMonospacedNumbersSelector)},
#{UIFontFeatureTypeIdentifierKey: #(kTextSpacingType), UIFontFeatureSelectorIdentifierKey: #(kMonospacedTextSelector)}];
countdownFontDescriptor = [countdownFontDescriptor fontDescriptorByAddingAttributes: #{UIFontDescriptorFeatureSettingsAttribute: additionalFontSettings}];
UIFont *desiredFont = [UIFont fontWithDescriptor:countdownFontDescriptor size:14];
I get monospaced numbers as they should appear, but I have semicolons in my string which separate the numbers. Occasionally I see this character move. How can I get the width of the semicolon to remain constant also? (This is why I tried adding kTextSpacingType)
Not sure but did you try looking in (as of Xcode 9.1 beta)
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/CoreText.framework/Headers/SFNTLayoutTypes.h.
I can't see a way to do it there, but maybe someone else can.
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]];
So my problem is that i have font witch supports osf (old style figures) but i don't know how to enable it with UIFont?
I have figured it out.
OSF is optional feature included in some fonts, so we need to activate this feature using
UIFontDescriptor *fontDescriptor = [UIFontDescriptor fontDescriptorWithFontAttributes:#{
UIFontDescriptorNameAttribute : #"MyriadPro-Light",
UIFontDescriptorFeatureSettingsAttribute : #[osfFontFeature]
}];
where osfFontFeature is
NSDictionary *osfFontFeature = #{
UIFontFeatureTypeIdentifierKey : #(21),
UIFontFeatureSelectorIdentifierKey : #(0)
};
Feature type and selector identifier keys can be obtained here:
https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type21
Finally, we create font with
[UIFont fontWithDescriptor:fontDescriptor size:17.0]
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.
My project demands that I use a custom Font, but this font have strange images in some characters like ( ) , . / etc...
The design agency said to replace the font in these characters to a more common font like Gill Sans.
So in a NSString = #"(My Favorite's. Love this!)";
I need to have the main custom font for the text and the Gill Sans font for the ( ' . ! and )
Is there a code where I can just pass the string and it returns some NSString with NSAttributedString with the font changes?
Thanks,
here is a sample code:
NSString *displayText = #"(My Favorite's. Love this!)";
NSMutableAttributedString *attributedString = [NSMutableAttributedString attributedStringWithString:displayText];
[attributedString setFont:[UIFont systemFontOfSize:15] range:[displayText rangeOfString:#"."]];
The last line will change the font of the point (.) to system font of size 15. You can search another characters in the string using the same function, and replace another properties of the string with setter methods of the form setX:range: of the NSAttributedString class.
Hope it helps!
use NSAttributedString to set multible font and size for string in ios NSAttributedString Class Reference,example