iOS - 如何为我的自定义字体设置备用字体?

10
我正在为我的应用程序导航栏标题使用粗体自定义字体。
我刚刚将我的应用程序本地化。 对于字体不支持的语言(主要是亚洲语言),iOS将退回到系统默认字体 - 不幸的是,这不是粗体系统默认字体,而是标准字体,不适合用作标题。
我该怎么做才能改变这种情况?

@ajnin,你的问题陈述与这个问题不同... - Wain
@Wain:不,我也有同样的问题。我有一个本地化为中文的应用程序,但有时服务器会提供英文名称。该应用程序使用系统默认字体显示英文字符。我想在英文字符上使用不同的字体,而不是系统默认字体。 - ninjaneer
你有没有考虑将下面的答案与响应/属性字符串的片段结合起来? - Wain
5个回答

4
+ (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;
}  

将“Helvetica Neue”更改为您想要的任何fontName作为备用字体,您将获得一个备用字体。

2

回答赏金问题

这里有一个扩展,可以使用第二组属性构建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
    }
}

示例用法:

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])

第二种方法

这个扩展允许您指定替换字体,而不是为特定字符使用第二个字体:

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
    }
}

示例用法:

let label = UILabel()
label.attributedText = "some текст".attributedString("Chalkduster", fallbackFontName: "Baskerville-SemiBoldItalic", fontSize: 18)

0

我不确定这是否是最好的方法,但我使用以下代码片段来检查特定语言:

//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];

0

基本上,如果语言不受支持,常规的if语句会替换自定义字体。换句话说,挑战在于找出所涉及的语言是否受支持。

解决方案可能不是最佳的,但我相信它应该有效:

  • 将字体转换为CGFontRef。CGFontRef cgFontVersion = CGFontCreateWithFontName((CFStringRef)uiFont.fontName);
  • 使用CGFontGetGlyphWithGlyphName用于包含您计划支持的每种语言的必要字形的数组。
  • 如果CGFontGetGlyphWithGlyphName返回0,则不支持您的自定义字体,您可以使用任何后备字体。

*获取这些可能是最困难的部分,好的一面是,您只需要做一次即可,并且可以在将来的项目中再次使用...

更实用的解决方案是像Hannes建议的那样做,但是对于您决定在未来使用的每个新自定义字体,您都需要为每种语言手动重新执行此操作。


-1
请确保您拥有所需的字体,以作为默认字体显示,而不是系统默认字体。但是,可以选择与所需字体类似的默认字体。
// 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 )
}

这样可以确保我们始终有一个可用的字体。现在,您可以从这里开始设置字体及其样式以获得首选视图/控件。

就这样了。请告诉我们您的使用情况如何!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接