on demand resources for fonts in Xamarin Forms - ios

Can we fetch font file .otf and .ttf files on demand in Xamarin ios? Below is the sample code to fetch the fonts in swift asynchronously. I'm looking for the same in C#.
{
(void)asynchronouslySetFontName:(NSString *)fontName toTextView:(UITextView *)textView {
CGFloat size = 24.0f;
UIFont *font = [UIFont fontWithName:fontName size:size];
if (font && ([font.fontName compare:fontName] == NSOrderedSame || [font.familyName compare:fontName] == NSOrderedSame)) {
textView.font = font;
return;
}
NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithObject:fontName forKey:kCTFontNameAttribute];
CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attrs);
NSMutableArray *descs = [NSMutableArray array];
[descs addObject:(__bridge id)desc];
CFRelease(desc);
__weak UITextView *weakTextView = textView;
CTFontDescriptorMatchFontDescriptorsWithProgressHandler((__bridge CFArrayRef)descs, NULL, ^(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {
if (state == kCTFontDescriptorMatchingDidFinish) {
dispatch_async(dispatch_get_main_queue(), ^{
weakTextView.font = [UIFont fontWithName:fontName size:size];
});
}
return YES;
});
}
}
I'm struggling to convert same code to Xamarin iOS c#? Is this feature compatible with Xamarin?

If you want to reduce the size of the application, you could try download fonts and install them at runtime. There is a similar issue on Github issue which you could refer to:
load fonts from web on demand. The accepted answer using Xamarin.Forms DependencyService to register Fonts at iOS runtime. But first you should download and put fonts file to Cache directory .
Hope it works for you.

Related

Avoid Bold effect ios Settings

I have more than 150 xibs in my app, I don't want to update the font for each xib, When I updates the font from settings to BOLD, it disturbs the font size of my app, I want to avoid that.
How can I avoid this?
Thanks in advance.
Hi You could Programmatically set the font as bold. Try This-
In Your View Controller. m -->
- (void)viewDidLoad
{
[super viewDidLoad];
[self makeFontLabel:self.label];
}
- (void)makeFontBold:(UILabel *)label
{
UIFont *labelFont = label.font;
UIFont *boldFont = [UIFont fontWithName:[NSString stringWithFormat:#"%#-Bold",labelFont.fontName] labelFont.pointSize];
label.font = boldFont;
}
Hope it helps you!

bold, italic using UIFontDescriptor

i have an UITextView that have some text and 2 buttons one to make selected texet bold anthor to make it italic
- (IBAction)boldedSelectedText:(UIButton*)sender {
UIFontDescriptor* bodyFontDescriptor=[UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
UIFontDescriptor* boldFontdescriptor=[bodyFontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold];
self.body.font=[UIFont fontWithDescriptor:boldFontdescriptor size:0.0];
}
- (IBAction)italicSelectedText:(UIButton *)sender {
UIFontDescriptor* bodyFontDescriptor=[UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFontTextStyleBody];
UIFontDescriptor* italicFontdescriptor=[bodyFontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic];
self.body.font=[UIFont fontWithDescriptor:italicFontdescriptor size:0.0];
}
the problem is when i select a text and make it bold then italic , it become italic only and vice
it can not be bold and italic at the same time i don't know why?
You need to retrieve the existing symbolic traits first, then add your new trait.
I use a helper method to add/remove my traits,
-(void) addOrRemoveFontTraitWithName:(NSString*)traitName andValue:(uint32_t)traitValue
{
NSMutableDictionary *attributes;
NSRange selectedRange=[self.attributedTextview selectedRange];
if (selectedRange.length == 0)
{
//no text selected
attributes=[[NSMutableDictionary alloc] initWithDictionary:self.attributedTextview.typingAttributes];
}
else
{
attributes=[[NSMutableDictionary alloc] initWithDictionary:[self.attributedTextview.textStorage attributesAtIndex:selectedRange.location effectiveRange:nil]];
}
UIFont *currentFont=[attributes objectForKey:NSFontAttributeName];
UIFontDescriptor *fontDescriptor=[currentFont fontDescriptor];
NSString *fontNameAttribute=[[fontDescriptor fontAttributes] objectForKey:UIFontDescriptorNameAttribute];
UIFontDescriptor *changedFontDescriptor;
if ([fontNameAttribute containsString:traitName])
{
uint32_t existingTraitsWithNewTrait=[fontDescriptor symbolicTraits] | traitValue;
changedFontDescriptor=[fontDescriptor fontDescriptorWithSymbolicTraits:existingTraitsWithNewTrait];
}
else
{
uint32_t existingTraitsWithoutTrait=[fontDescriptor symbolicTraits] & ~traitValue;
changedFontDescriptor=[fontDescriptor fontDescriptorWithSymbolicTraits:existingTraitsWithoutTrait];
}
UIFont *updatedFont=[UIFont fontWithDescriptor:changedFontDescriptor size:0.0];
[attributes setObject:updatedFont forKey:NSFontAttributeName];
if (selectedRange.length != 0)
{
[self.attributedTextview.textStorage beginEditing];
[self.attributedTextview.textStorage setAttributes:attributes range:selectedRange];
[self.attributedTextview.textStorage endEditing];
}
[self.attributedTextview setTypingAttributes:attributes];
}
If the user has selected some text, the trait is applied to that specific selection, otherwise it is applied to the textview's typingAttributes property.
A bitwise operation is required to add/remove the trait.
This article covers this subject in some detail and is well worth a read
Using Text Kit to Manage and Draw Text in IOS Apps
Regards

What method do you call to get the user's preferred text size?

iOS has a method that you call that will tell you a user's selected Dynamic Type text size (which they set in Settings > General > Text Size and has 7 possible values from small to large).
There is an API call that you can make, that returns one of seven string values that describe these seven options, but I can't seem to find it. I know it exists as I've used it before, but I can't find it anywhere.
Note: I am not talking about this method:
[UIFont preferredFontForTextStyle:UIFontTextStyleBody]
which returns a UIFont.
Swift 4:
This is what I am using to determine the current font category in Swift.
let fontCategory = UIApplication.shared.preferredContentSizeCategory
switch fontCategory {
case UIContentSizeCategory.accessibilityExtraExtraExtraLarge:
print("A_XXXL")
case UIContentSizeCategory.accessibilityExtraExtraLarge:
print("A_XXL")
case UIContentSizeCategory.accessibilityExtraLarge:
print("A_XL")
case UIContentSizeCategory.accessibilityLarge:
print("A_L")
case UIContentSizeCategory.accessibilityMedium:
print("A_M")
case UIContentSizeCategory.extraExtraExtraLarge:
print("XXXL")
case UIContentSizeCategory.extraExtraLarge:
print("XXL")
case UIContentSizeCategory.extraLarge:
print("XL")
case UIContentSizeCategory.large:
print("L")
case UIContentSizeCategory.medium:
print("M")
case UIContentSizeCategory.small:
print("S")
case UIContentSizeCategory.extraSmall:
print("XS")
case UIContentSizeCategory.unspecified:
print("Unspecified")
default:
print("Unknown")
}
Found it, it's [[UIApplication sharedApplication] preferredContentSizeCategory]. Here's some code you can use to get this property and turn it into whatever scale of font sizes you like:
CGFloat fontSize = 17;
NSString *textSize = [[UIApplication sharedApplication]
preferredContentSizeCategory];
if ([textSize isEqualToString:#"UICTContentSizeCategoryXS"]) {
fontSize = 10;
} else if ([textSize isEqualToString:#"UICTContentSizeCategoryS"]) {
fontSize = 13;
} else if ([textSize isEqualToString:#"UICTContentSizeCategoryM"]) {
fontSize = 15;
} else if ([textSize isEqualToString:#"UICTContentSizeCategoryL"]) {
// "Normal" or middle size - use designed font sizes
fontSize = 17;
} else if ([textSize isEqualToString:#"UICTContentSizeCategoryXL"]) {
fontSize = 24;
} else if ([textSize isEqualToString:#"UICTContentSizeCategoryXXL"]) {
fontSize = 32;
} else if ([textSize isEqualToString:#"UICTContentSizeCategoryXXXL"]) {
fontSize = 48;
}
Actually, it seems that it is that method, based on this page:
To take advantage of these features, be prepared to respond to the notifications that get sent when users change the text size setting. Then, use the UIFont method preferredFontForTextStyle to get the new font to use in your UI. iOS 7 optimizes fonts that are specified by this method for maximum legibility at every size. To learn more about text styles and using fonts in your app, see “Text Styles” in Text Programming Guide for iOS.
Additionally, the documentation for +[UIFont preferredFontForTextStyle:] explicitly says that it returns "an instance of the font associated with the text style and scaled appropriately for the user's selected content size category." In other words, the returned UIFont is already scaled to the user's preferences.
You can obtain the font size from the UIFont by using -[UIFont pointSize].
Kind of late to answer this question, but just wanted to add this for completeness.
Here is the documentation on preferredContentSizeCategory
https://developer.apple.com/documentation/uikit/uiapplication/1623048-preferredcontentsizecategory?language=objc
And here is the documentation for defined content size constants
https://developer.apple.com/documentation/uikit/uicontentsizecategory?language=objc
Example usage:
- (void) viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didChangePreferredContentSize:)
name:UIContentSizeCategoryDidChangeNotification
object:nil];
[self didChangePreferredContentSize: nil];
}
- (void) didChangePreferredContentSize: (NSNotification *) notification {
CGFloat pointSize = [UIFontDescriptor preferredFontDescriptorWithTextStyle: UIFontTextStyleCaption2].pointSize;
CGFloat pointSizeForRegularFonts = [UIFontDescriptor preferredFontDescriptorWithTextStyle: UIFontTextStyleSubheadline].pointSize;
// NSString *newFontSize = notification.userInfo[UIContentSizeCategoryNewValueKey];
NSString *newFontSize = [UIApplication sharedApplication].preferredContentSizeCategory;
if ([newFontSize isEqualToString: UIContentSizeCategoryExtraSmall] ||
[newFontSize isEqualToString: UIContentSizeCategorySmall] ||
[newFontSize isEqualToString: UIContentSizeCategoryMedium] ||
[newFontSize isEqualToString: UIContentSizeCategoryLarge] ||
[newFontSize isEqualToString: UIContentSizeCategoryAccessibilityMedium] ||
[newFontSize isEqualToString: UIContentSizeCategoryAccessibilityLarge]) {
pointSize = pointSizeForRegularFonts;
}
[self.descriptionLabel setFont: [UIFont systemFontOfSize: pointSize]];
[self.button.titleLabel setFont: [UIFont systemFontOfSize: pointSize]];
}

ios apps can download the following fonts if necessary

In the iOS 7 font list located here, http://support.apple.com/kb/HT5878, there is a section at the bottom with the heading "apps can download the following fonts if necessary".
What does this mean?
How does one include these fonts, and how is this different than including custom fonts?
This is interesting, it's an almost undocumented feature, but it seems ok to use and won't get your app rejected. Just trying to research this myself brought me to this question and not much else. All I could find that was documented is sample code showing how to use it: DownloadFont.
Demonstrates how to download fonts on demand on iOS 6 and later.
On iOS 6, we have added the capability for applications to download fonts on demand. Besides the fonts installed with iOS 6, applications can install a list of additional fonts as necessary.
The fonts listed are already licensed by Apple for use in iOS, however they aren't bundled with the standard iOS firmware due to the extra disk space usage. I would assume that this will continue to be how Apple provides new fonts (unless a part of the OS's UI uses it). Additionally, unlike adding fonts using the UIAppFonts key in your Info.plist, after the font is downloaded, it is available for all apps to use.
Here's a simple example on how to asynchronously download a font and set it to a UITextView.
- (void)asynchronouslySetFontName:(NSString *)fontName toTextView:(UITextView *)textView {
CGFloat size = 24.0f;
UIFont *font = [UIFont fontWithName:fontName size:size];
if (font && ([font.fontName compare:fontName] == NSOrderedSame || [font.familyName compare:fontName] == NSOrderedSame)) {
textView.font = font;
return;
}
NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithObject:fontName forKey:kCTFontNameAttribute];
CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attrs);
NSMutableArray *descs = [NSMutableArray array];
[descs addObject:(__bridge id)desc];
CFRelease(desc);
__weak UITextView *weakTextView = textView;
CTFontDescriptorMatchFontDescriptorsWithProgressHandler((__bridge CFArrayRef)descs, NULL, ^(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {
if (state == kCTFontDescriptorMatchingDidFinish) {
dispatch_async(dispatch_get_main_queue(), ^{
weakTextView.font = [UIFont fontWithName:fontName size:size];
});
}
return YES;
});
}
And here's a list of all the downloadable fonts. http://iosfontlist.com

How do I create a bold UIFont from a regular UIFont?

If I have a UIFont object, is it possible to convert it to bold? I don't know the font name, I just have a UIFont object. What I want is a function like
UIFont *boldFontFromFont(UIFont *input)
{
return [input derivedFontWithFontWeight:UIFontWeightBold];
}
How can I change the code so that it works. (The code above does not work, I just made it up to illustrate the point.)
Thanks in advance.
iOS 7 introduces a new UIFontDescriptor class, which makes it a lot easier:
UIFont *font = [UIFont fontWithName:#"Helvetica Neue" size:12];
NSLog(#"plain font: %#", font.fontName); // “HelveticaNeue”
UIFont *boldFont = [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold] size:font.pointSize];
NSLog(#"bold version: %#", boldFont.fontName); // “HelveticaNeue-Bold”
UIFont *italicFont = [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitItalic] size:font.pointSize];
NSLog(#"italic version: %#", italicFont.fontName); // “HelveticaNeue-Italic”
UIFont *boldItalicFont = [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold | UIFontDescriptorTraitItalic] size:font.pointSize];
NSLog(#"bold & italic version: %#", boldItalicFont.fontName); // “HelveticaNeue-BoldItalic”
For people who got here looking for a Cocoa (macOS) equivalent, UIFontDescriptor comes from NSFontDescriptor, available since 10.3.
And if you are looking for the swift implementation:
let normalFont = UIFont(name: "FONT_NAME", size: CGFloat(20))!
let boldFont = UIFont(descriptor: normalFont.fontDescriptor.withSymbolicTraits(.traitBold)!, size: normalFont.pointSize)
Hope this helps! Cheers!
To get a bold font you need to pass a specific name of the font from a font family. You can get a font family name from a given font, then list all fonts from this family. In general, a bold font will contain "bold" in its name, but the format isn't strict and there could be variations like "Helvetica-BoldOblique", for example. You can start from this code:
- (UIFont *)boldFontFromFont:(UIFont *)font
{
NSString *familyName = [font familyName];
NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName];
for (NSString *fontName in fontNames)
{
if ([fontName rangeOfString:#"bold" options:NSCaseInsensitiveSearch].location != NSNotFound)
{
UIFont *boldFont = [UIFont fontWithName:fontName size:font.pointSize];
return boldFont;
}
}
return nil;
}
This is a very old thread but someone may be interested in how to do this in Swift 5 nowadays.
Easy like this:
var font: UIFont = UIFont.systemFont(ofSize: 18)
if let newDescriptor = font.fontDescriptor.withSymbolicTraits(.traitBold) {
font = UIFont(descriptor: newDescriptor, size: font.pointSize)
}
Attempting to derive the bold/italic font using font or family names no longer works correctly since iOS 7, due to the cryptic font family name of the system font. Below is a simple extension to derive the bold/italic font using the UIFontDescriptor class.
+(UIFont *) font:(UIFont *)font bold:(BOOL)bold italic:(BOOL)italic
{
NSUInteger traits = 0;
if (bold)
{
traits |= UIFontDescriptorTraitBold;
}
if (italic)
{
traits |= UIFontDescriptorTraitItalic;
}
return [UIFont fontWithDescriptor:[[font fontDescriptor] fontDescriptorWithSymbolicTraits:traits] size:font.pointSize];
}
You can either use
[UIFont boldSystemFontOfSize:12].
If you are using custom fonts you have to use the name directly
[UIFont fontWithName:#"Helvetica-Bold" size:17.0].
You can look up the possible font names with
[UIFont fontNamesForFamilyName:#"American Typewriter"].
In this Post: https://stackoverflow.com/a/15388946/436818 Ben M has an idea how to get the bold version dynamically. But extend the method to be sure to get the bold version (if it exists) because there are other bold versions like CondensedBold too.
Since this question pops up when you search for bold UIFonts in Swift, here's a fresh answer:
extension UIFont {
/// Returns a new font in the same family with the given symbolic traits,
/// or `nil` if none found in the system.
func withSymbolicTraits(_ traits: UIFontDescriptor.SymbolicTraits) -> UIFont? {
guard let descriptorWithTraits = fontDescriptor.withSymbolicTraits(traits)
else { return nil }
return UIFont(descriptor: descriptorWithTraits, size: 0)
}
}
Example:
myFont.withSymbolicTraits(.taitBold) // returns the bold version of myFont
Nobody posted a solution which:
is for Swift
is an extension for UIFont
doesn't do force unwraps
uses the same point size as source font
and only does what is asked in the question (create bold UIFont based on existing UIFont)
so I'm doing it:
import UIKit
extension UIFont {
func boldFont() -> UIFont? {
guard let boldDescriptor = fontDescriptor.withSymbolicTraits(.traitBold) else {
return nil
}
return UIFont(descriptor: boldDescriptor, size: pointSize)
}
}
Feel free to copy-and-paste!

Resources