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]
Related
I can easily use TTTAttributedlabel to have tappable url, name, etc.
1) How can I create something similar to that in CKLabelComponent?
2) Do I need to use CKTextComponent?
[CKLabelComponent newWithLabelAttributes:{
.string = #"This shall be context This shall be context This shall be context This shall be context",
.font = [UIFont fontWithName:#"Baskerville" size:14]
}
viewAttributes:{
{#selector(setBackgroundColor:), [UIColor clearColor]},
{#selector(setUserInteractionEnabled:), #NO},
}
size:{ }]
You could make you component easily. Provide the view, implement the computeLayoutThatFits:. CKImageComponent is an example.
But at the situation of text. It may be hard, because of the layout size. Once you use TTTAttributedLabel as the render of text, you have to provide the text size manually. This is definitely not the thing you want.
As you could see, CKTextComponent, the parent of CKLabelComponent, is implemented as a subproject of ComponentKit. It handle the layout size, text rendering, text layout cache. (It's implemented with TextKit.) If you want to use TTTAttributedLabel, you have to handle all things yourself with TTTAttributedLabel. It may slow down your scroll, because CKTextComponent implement async render but TTTAttributedLabel don't.
CKTextKitEntityAttributeName may achieve your goal
My way is to combine CK with TTTAttributedLabel. First, I define a struct, it contains some basic info I need to set to TTTAttributedLabel,
struct ABCKAttributeLabelData {
NSString *content;
UIFont *normalFont;
UIColor *normalColor;
UIFont *linkFont;
UIColor *linkColor;
NSInteger numberOfLines;
};
Then, I create a new class, named ABCKAttributeLabelComponent subclass of CKComponent, implemented initialize method as below:
+ (instancetype)newWithData:(ABCKAttributeLabelData)data {
ABCKAttributeLabelComponent *com =
[super newWithView:{
[TTTAttributedLabel class],
{
{#selector(setText:), [data.content attributedStringWithStyle:
#{NSForegroundColorAttributeName : data.normalColor,
NSFontAttributeName : data.normalFont,}]},
{#selector(setLinkAttributes:), #{ NSForegroundColorAttributeName : data.linkColor,
NSFontAttributeName : data.linkFont}},
{#selector(setActiveLinkAttributes:), #{ NSForegroundColorAttributeName : data.linkColor,
NSFontAttributeName : data.linkFont}},
{#selector(setNumberOfLines:), data.numberOfLines ?: 0},
{#selector(setLineBreakMode:), NSLineBreakByTruncatingTail},
}
} size:{}];
com.attributeString = [data.content attributedStringWithStyle:
#{NSForegroundColorAttributeName : data.normalColor,
NSFontAttributeName : data.normalFont,}];
com.normalFont = data.normalFont;
com.numOfLine = data.numberOfLines ?: 0;
return com
Third, calculate TTTAttributedLabel's size and return. CK will call computeLayoutThatFits: method to get component size. So overwrite it.
- (CKComponentLayout)computeLayoutThatFits:(CKSizeRange)constrainedSize {
// self.attributeString,self.numOfLine and self.normalFont I saved as property in initialize method
CGSize computerSize = [self.attributeString sizeLabelToFitToSize:constrainedSize.max numberLines:self.numOfLine font:self.normalFont];
return {
self,
constrainedSize.clamp({
CKCeilPixelValue(computerSize.width),
CKCeilPixelValue(computerSize.height)
}),
{}
};
}
The rest of the things is to use ABCKAttributeLabelComponent.
it may not be very elegance, but it can works.
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]];
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.
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.