简体   繁体   English

iOS-如何为自定义字体设置后备字体?

[英]iOS - How can I set a fallback font for my custom font?

I'm using a bold custom font for my app's navigation bar titles. 我为我的应用程序的导航栏标题使用了粗体的自定义字体。

I've also just localised my app. 我也刚刚本地化了我的应用程序。 For languages the font doesn't support (primarily Asian languages), iOS falls back to the system default - alas, this is not a bold system default but a standard weighting not suitable for headings. 对于字体不支持的语言(主要是亚洲语言),iOS会退回到系统默认值-las,这不是粗体的系统默认值,而是不适合标题的标准权重。

What can I do to change this? 我该怎么做才能改变呢?

Answer to the bounty question 悬赏问题的答案

Here is an extension allowing to construct NSAttributedString with a second set of attributes that will be applied to latin characters: 这是一个扩展,允许使用第二组属性构造NSAttributedString,这些属性将应用于拉丁字符:

extension String {
    private var englishRanges: [NSRange] {
        let set = NSMutableCharacterSet(range: NSRange(location: 0x0041, length: 26))
        set.addCharactersInRange(NSRange(location: 0x0061, length: 26))
        var start = startIndex
        var englishRanges = [Range<String.Index>]()
        while let range = rangeOfCharacterFromSet(set, options: [], range: start..<endIndex) {
            start = range.endIndex
            englishRanges.append(range)
        }
        return englishRanges.map {NSRange(location: startIndex.distanceTo($0.startIndex), length: $0.count)}
    }

    func attributedMultilanguageString(options: [String:AnyObject], englishOptions:[String:AnyObject]) -> NSAttributedString {
        let string = NSMutableAttributedString(string: self, attributes: options)
        englishRanges.forEach {
            string.setAttributes(englishOptions, range: $0)
        }
        return string
    }
}

Example usage: 用法示例:

let font = UIFont(name: "Arial-BoldMT", size: 18.0)!
let englishFont = UIFont(name: "Chalkduster", size: 18.0)!
let label = UILabel()
label.attributedText = "some string 111".attributedMultilanguageString([ NSFontAttributeName: font], englishOptions: [ NSFontAttributeName: englishFont])

Second approach 第二种方法

And this extension allows you to specify fallback font instead of using a second font for specific characters: 并且此扩展允许您指定后备字体,而不是对特定字符使用第二种字体:

extension String {
    private func unsupportedCharacterIndexes(font: String) -> [String.Index] {
        let font = CGFontCreateWithFontName(font)
        return characters.indices.filter {CGFontGetGlyphWithGlyphName(font, String(self[$0])) == 0}
    }

    func attributedString(fontName: String, fallbackFontName: String, fontSize: CGFloat, options: [String:AnyObject]? = nil) -> NSAttributedString {
        var options = options ?? [String:AnyObject]()
        options[NSFontAttributeName] = UIFont(name: fontName, size: fontSize)
        let string = NSMutableAttributedString(string: self, attributes: options)
        options[NSFontAttributeName] = UIFont(name: fallbackFontName, size: fontSize)
        unsupportedCharacterIndexes(fontName).forEach {
            string.setAttributes(options, range: NSRange(location: startIndex.distanceTo($0), length: 1))
        }
        return string
    }
}

Example usage: 用法示例:

let label = UILabel()
label.attributedText = "some текст".attributedString("Chalkduster", fallbackFontName: "Baskerville-SemiBoldItalic", fontSize: 18)
+ (UIFont *)addFallbacktoFont:(UIFont*)font{
   UIFontDescriptor* originalDescriptor = [font fontDescriptor];

   UIFontDescriptor* fallbackDescriptor = [originalDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorNameAttribute:@"Helvetica Neue"}];

   UIFontDescriptor* repaired = [originalDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorCascadeListAttribute:@[
                                                                                            fallbackDescriptor
                                                                                            ]}];

   font = [UIFont fontWithDescriptor:repaired size:0.0];

   return font;
}  

Change "Helvetica Neue" to any fontName you want to fall back,and you will get a fallback Font. 将“ Helvetica Neue”更改为要回退的任何fontName,您将获得一个回退字体。

I'm not sure if it's the best way but I use the following snippet to check for specific languages: 我不确定这是否是最佳方法,但是我使用以下代码段检查特定语言:

//store all fallback languages in this array (eg.: el = greek, ru = russian)
NSArray *fallbackFont = @[@"el", @"ru"];
NSString *lang = [[NSLocale preferredLanguages] objectAtIndex:0]
BOOL hasFallbackFont = [fallbackFont containsObject:lang];

NSString *fontNameBold = hasFallbackFont ? @"Fallback-Font-Bold" : @"Regular-Font-Bold";

...

myLabel.font = [UIFont fontWithName:fontNameBold size:12.0];

The basic is of course a regular if to replace the custom font if the language is not supported. 如果不支持自定义字体,则基本语言当然是常规语言。 The challenge is in other words to find out whether the language in question is supported or not. 换句话说,挑战在于找出是否支持所讨论的语言。

Not the sexiest of solutions, but I believe it should work: 不是最性感的解决方案,但我认为它应该起作用:

  • Convert your font to a CGFontRef. 将字体转换为CGFontRef。 CGFontRef cgFontVersion = CGFontCreateWithFontName((CFStringRef)uiFont.fontName);
  • use CGFontGetGlyphWithGlyphName towards an array containing the necessary glyphs from each language you plan to support.* 对包含您打算支持的每种语言的必要字形的数组使用CGFontGetGlyphWithGlyphName 。*
  • If CGFontGetGlyphWithGlyphName returns 0 your custom font is NOT supported and you can use whatever fall-back-font you would like. 如果CGFontGetGlyphWithGlyphName返回0,则不支持您的自定义字体,您可以使用所需的任何后备字体。

*getting hold of these might be the hardest part, the nice part as that you'd only need to do this once and could use it again for future projects... *掌握这些可能是最困难的部分,这是一个很好的部分,因为您只需要执行一次就可以将其再次用于将来的项目...

A more pragmatic solution would be to do something like Hannes suggests, but then you would need to redo it for each language manually for every new custom font you decide to use in the future. 更加实用的解决方案是像Hannes所建议的那样做,但是随后您将需要为将来决定使用的每种新自定义字体手动为每种语言重做。

Please ensure you have the desired font you want to display as default font, not the system default. 请确保您具有要显示为默认字体而不是系统默认字体的所需字体。 But, something similar to the desired font, a default. 但是,类似于所需字体的默认值。

// Method that returns the font for buttons and title bar
// Pass in your custom font as a string argument/ parameter
func getFont(fontName: String, size fontSize: CGFloat)-> UIFont {

// Unwrap your custom font here, if font exists "Hooray!" else "Bo-Oh!" return a default one
if let customFont = UIFont(named: fontName, size: fontSize ) {
  return customFont
} else {
// This gets the system default font and returns to you!
  return UIFont(named: defaultFont, size: fontSize )
}

This ensure we always have a font to use. 这样可以确保我们始终使用字体。 Now, you can take the rest from here on how to set the font and its style to the preferred view/controls. 现在,您可以从此处开始其他内容,了解如何将字体及其样式设置为首选视图/控件。

That should do it. 那应该做。 Do tell us about how it goes for you! 请告诉我们有关您情况的信息!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM