为整个iOS应用设置默认字体?

173

我有一个自定义字体,希望在我的应用程序中显示的所有文本(标签,文本视图等)都使用该字体。

有没有一种方法可以为整个应用程序设置默认字体(标签默认使用 SystemFont)?


7
经过大量的调查研究,我们发现最简单的做法就是为每个控件创建一个(微不足道的)新类。例如,对于 UIButton,创建 SJButton。不要忘记覆盖 initWithFrame 和 initWithCode。对于每个控件(如 UIButton 等),设置颜色或您喜欢的任何其他属性。在 int 代码中仔细选择所需的大小(即在 Storyboard 上设置的大小),然后根据需要使用该大小(并设置字体、颜色等)。这只需要几行代码,非常整洁,可以节省大量的时间。 - Fattie
@JoeBlow 感谢您发布您的发现 - 我本来要花时间找答案的。 - jj.
@jj- 对的。别忘了,现在一定要使用IBDesignable。希望能有所帮助。另外,考虑一下这个有趣的QA:https://dev59.com/questions/JZjga4cB1Zd3GeqPIVHJ#38000466 - Fattie
17个回答

160

看起来在iOS 5中使用UIAppearance代理是可能的。

 [[UILabel appearance] setFont:[UIFont fontWithName:@"YourFontName" size:17.0]];

这将为你的应用程序中的所有UILabel设置字体为你自定义的字体。 你需要为每个控件(UIButton,UILabel等)重复此步骤。

请注意,您需要在info.plist中添加UIAppFonts值并包含您要添加的字体的名称。


48
谢谢回复。我已经成功让它运行了。你知道有没有一种方法可以指定字体而不指定字号吗?我在我的应用程序中有标签,它们的字体大小不相同。 - Brandon
23
我能否在不覆盖每个实例的点大小的情况下完成这个操作? - Michael Forrest
17
setFont: 方法已被弃用。 - Anand
12
@Anand你确定这件事吗?我没有看到UILabel中标记为已弃用。它对于UIButton而言是被弃用的,但是它仍然可以使用在titleLabel属性上的字体,该属性对应的是一个UILabel,因此只需使用UILabel的外观代理来设置字体就可以了。 - Adrian Schönig
6
@Anand,对于UILabel来说它并没有过时。 - Alastair Stuart
显示剩余10条评论

139

Swift 5

根据 Fábio Oliveira 的回答 (https://dev59.com/12oy5IYBdhLWcg3wMLSj#23042694),我制作了自己的 Swift 4 扩展。

简而言之,这个扩展更改了默认函数 init(coder:)systemFont(ofSize:)boldSystemFont(ofSize:)italicSystemFont(ofSize:),用我的自定义方法代替它们。

请注意,这并不是完全实现,但你可以根据我的实现交换更多的方法。

import UIKit

struct AppFontName {
    static let regular = "CourierNewPSMT"
    static let bold = "CourierNewPS-BoldMT"
    static let italic = "CourierNewPS-ItalicMT"
}

extension UIFontDescriptor.AttributeName {
    static let nsctFontUIUsage = UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute")
}

extension UIFont {
    static var isOverrided: Bool = false

    @objc class func mySystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: AppFontName.regular, size: size)!
    }

    @objc class func myBoldSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: AppFontName.bold, size: size)!
    }

    @objc class func myItalicSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: AppFontName.italic, size: size)!
    }

    @objc convenience init(myCoder aDecoder: NSCoder) {
        guard
            let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor,
            let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String else {
                self.init(myCoder: aDecoder)
                return
        }
        var fontName = ""
        switch fontAttribute {
        case "CTFontRegularUsage":
            fontName = AppFontName.regular
        case "CTFontEmphasizedUsage", "CTFontBoldUsage":
            fontName = AppFontName.bold
        case "CTFontObliqueUsage":
            fontName = AppFontName.italic
        default:
            fontName = AppFontName.regular
        }
        self.init(name: fontName, size: fontDescriptor.pointSize)!
    }

    class func overrideInitialize() {
        guard self == UIFont.self, !isOverrided else { return }

        // Avoid method swizzling run twice and revert to original initialize function
        isOverrided = true

        if let systemFontMethod = class_getClassMethod(self, #selector(systemFont(ofSize:))),
            let mySystemFontMethod = class_getClassMethod(self, #selector(mySystemFont(ofSize:))) {
            method_exchangeImplementations(systemFontMethod, mySystemFontMethod)
        }

        if let boldSystemFontMethod = class_getClassMethod(self, #selector(boldSystemFont(ofSize:))),
            let myBoldSystemFontMethod = class_getClassMethod(self, #selector(myBoldSystemFont(ofSize:))) {
            method_exchangeImplementations(boldSystemFontMethod, myBoldSystemFontMethod)
        }

        if let italicSystemFontMethod = class_getClassMethod(self, #selector(italicSystemFont(ofSize:))),
            let myItalicSystemFontMethod = class_getClassMethod(self, #selector(myItalicSystemFont(ofSize:))) {
            method_exchangeImplementations(italicSystemFontMethod, myItalicSystemFontMethod)
        }

        if let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:))), // Trick to get over the lack of UIFont.init(coder:))
            let myInitCoderMethod = class_getInstanceMethod(self, #selector(UIFont.init(myCoder:))) {
            method_exchangeImplementations(initCoderMethod, myInitCoderMethod)
        }
    }
}


class AppDelegate: UIResponder, UIApplicationDelegate {
    // Avoid warning of Swift
    // Method 'initialize()' defines Objective-C class method 'initialize', which is not guaranteed to be invoked by Swift and will be disallowed in future versions
    override init() {
        super.init()
        UIFont.overrideInitialize()
    }
    ...
}

2
最佳答案!!自动覆盖系统字体,太棒了。 - Kappe
2
如果有人遇到“NSCTFontUIUsageAttribute”这一行的问题:if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String {,这个方法对我很有帮助。 - DrDirk
1
似乎无法与设置文本样式(粗体,标题,大标题等)的UILabel一起使用...只能与具有特定字号和系统字体集的字体一起使用。 @nahung89 - Aviran
1
这也会切换一些系统UI字体。例如,键盘建议列表和操作表。不知道这是否会导致苹果拒绝该应用程序。 - Henry H Miao
1
我已经使用了上面的代码,它完美地工作了。但是我遇到了一个问题。我有两种语言:“英语”和“泰语”。当我切换到泰语时,我的密码安全文本字段不显示文本。这就是为令我想要停止上面的代码对于一个文本字段的影响。请帮我解决这个问题。谢谢。 - Jay Bhalani
显示剩余15条评论

75

还有另外一种解决方案,那就是覆盖系统字体。

只需创建一个分类

UIFont+SystemFontOverride.h

#import <UIKit/UIKit.h>

@interface UIFont (SystemFontOverride)
@end

UIFont+SystemFontOverride.m

@implementation UIFont (SystemFontOverride)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

+ (UIFont *)boldSystemFontOfSize:(CGFloat)fontSize {
    return [UIFont fontWithName:@"fontName" size:fontSize];
}

+ (UIFont *)systemFontOfSize:(CGFloat)fontSize {
    return [UIFont fontWithName:@"fontName" size:fontSize];
}

#pragma clang diagnostic pop

@end

这将替换默认实现,大多数 UIControls 使用 systemFont。


1
这符合苹果的指南吗? - Rambatino
这更像是一个hack。我没有使用任何私有方法,因此我的应用程序未在此hack中注册。如果您想要更强大的解决方案,我还建议您检查一下这个:https://github.com/0xced/FontReplacer - Hugues BR
2
这没问题。苹果只是不希望您使用未记录的函数。您可以“swizzle”公共方法。 - mxcl
4
当一个分类拥有与它所扩展的类相同签名(方法名和参数类型)的方法时,其行为是未定义的。如果要替换类方法,应该使用方法交换(但这也不是一个好主意)。 - GreatWiz
1
正如其他人指出的那样,这个解决方案虽然在大多数情况下可能是有效的,但在技术上引入了潜在的未定义行为的可能性。如果您不想冒险,方法交换可能是一个更好的选择。这里的答案通过交换提供了相同的解决方案:https://dev59.com/aXjZa4cB1Zd3GeqPcU2J - Nathan Hosselton
显示剩余8条评论

70

如果您正在使用Swift,可以创建一个UILabel扩展:

extension UILabel {

    @objc var substituteFontName : String {
        get { return self.font.fontName }
        set { self.font = UIFont(name: newValue, size: self.font.pointSize) }
    }

}

然后在你进行外观代理的地方:

UILabel.appearance().substituteFontName = applicationFont

有等价的Objective-C代码,使用UI_APPEARANCE_SELECTOR在名为substituteFontName的属性上。

补充

如果您想单独设置粗体和正常字体:

extension UILabel {

    @objc var substituteFontName : String {
        get { return self.font.fontName }
        set { 
            if self.font.fontName.range(of:"Medium") == nil { 
                self.font = UIFont(name: newValue, size: self.font.pointSize)
            }
        }
    }

    @objc var substituteFontNameBold : String {
        get { return self.font.fontName }
        set { 
            if self.font.fontName.range(of:"Medium") != nil { 
                self.font = UIFont(name: newValue, size: self.font.pointSize)
            }
        }
    }
}

然后针对您的UIAppearance代理:

UILabel.appearance().substituteFontName = applicationFont
UILabel.appearance().substituteFontNameBold = applicationFontBold
注意:如果您发现粗体替换无效,则可能默认字体名称不包含“Medium”。根据需要将该字符串替换为另一个匹配项(感谢下面评论中的Mason)。

我发现这种方法的一个缺点是,当我使用UIAlertController来初始化警报时,具有.Cancel样式的按钮与具有.Default样式的按钮相同(至少在使用GillSans时是这样)。而通常情况下,.Cancel将是常规字重,而.Default将是粗体。有什么想法吗? - Mason G. Zhwiti
2
在这种情况下,我很可能会设置“UILabel”扩展以获取一个额外的粗体字体名称。然后在“set”中进行检查,以查看字体名称中是否包含“Bold”,并在一种情况下忽略设置,在另一种情况下使用它。我会编辑并添加一个例子。 - Sandy Chapman
@SandyChapman 谢谢!我正在尝试这种新技术,它很有道理,但似乎对我不起作用。我在iOS 8.3模拟器上使用GillSans和GillSans-Bold字体。你测试过这种技术吗? - Mason G. Zhwiti
@MasonG.Zhwiti 我没有测试过这个。我已经好几个月没有进行任何Swift编程了。我建议在设置/加载字体的位置设置断点,并确保它们被正确设置。此外,字体名称不一定与字体文件名称匹配,所以要注意这一点。我建议使用这个来打印出应用程序中所有可用字体的名称。 - Sandy Chapman
2
@SandyChapman 我弄清楚了发生了什么。iOS 8的默认字体通常是HelveticaNeueInterface-Regular或(加粗时)HelveticaNeueInterface-MediumP4。因此,寻找“Bold”从来没有匹配到任何内容。我将其更改为rangeOfString("Medium"),然后它就可以工作了。 - Mason G. Zhwiti
显示剩余5条评论

22

参考Hugues BR的回答,但是使用方法交换(Method Swizzling)的方式,我成功地把我的应用中所有字体都改为了期望的字体。

iOS 7上应该采用Dynamic Type方法。以下解决方案不使用Dynamic Type。


注意事项:

  • 下面的代码并没有提交给Apple进行审批;
  • 有一个更短的版本通过了苹果的审核,即没有- initWithCoder:覆写。然而这并不能涵盖所有情况;
  • 下面的代码存在于我用于设置应用风格的类中,此类被我的AppDelegate类包含,在任何地方和任何UIFont实例中均可使用;
  • 我在这里使用Zapfino仅是为了使更改更加明显;
  • 如果你能对这个代码做出任何改进,欢迎分享。

这个解决方案使用了两种不同的方法来达到最终结果。第一种是覆盖UIFont类方法+ systemFontWithSize:和使用我的替代方法的类似方法(在这里我使用“Zapfino”以确保替换成功)。

另一种方法是覆盖UIFont的- initWithCoder:方法,将任何出现的CTFontRegularUsage和类似的内容都替换为我的替代方法。 这种方法是必要的,因为我发现在NIB文件中编码的UILabel对象不会检查+ systemFontWithSize:方法来获取它们的系统字体,而是将它们编码为UICTFontDescriptor对象。 我尝试覆盖- awakeAfterUsingCoder:,但不知何故它为我的Storyboard中的每个编码对象都调用了一次,导致崩溃。覆盖- awakeFromNib则无法读取NSCoder对象。

#import <objc/runtime.h>

NSString *const FORegularFontName = @"Zapfino";
NSString *const FOBoldFontName = @"Zapfino";
NSString *const FOItalicFontName = @"Zapfino";

#pragma mark - UIFont category
@implementation UIFont (CustomFonts)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+ (void)replaceClassSelector:(SEL)originalSelector withSelector:(SEL)modifiedSelector {
    Method originalMethod = class_getClassMethod(self, originalSelector);
    Method modifiedMethod = class_getClassMethod(self, modifiedSelector);
    method_exchangeImplementations(originalMethod, modifiedMethod);
}

+ (void)replaceInstanceSelector:(SEL)originalSelector withSelector:(SEL)modifiedSelector {
    Method originalDecoderMethod = class_getInstanceMethod(self, originalSelector);
    Method modifiedDecoderMethod = class_getInstanceMethod(self, modifiedSelector);
    method_exchangeImplementations(originalDecoderMethod, modifiedDecoderMethod);
}

+ (UIFont *)regularFontWithSize:(CGFloat)size
{
    return [UIFont fontWithName:FORegularFontName size:size];
}

+ (UIFont *)boldFontWithSize:(CGFloat)size
{
    return [UIFont fontWithName:FOBoldFontName size:size];
}

+ (UIFont *)italicFontOfSize:(CGFloat)fontSize
{
    return [UIFont fontWithName:FOItalicFontName size:fontSize];
}

- (id)initCustomWithCoder:(NSCoder *)aDecoder {
    BOOL result = [aDecoder containsValueForKey:@"UIFontDescriptor"];

    if (result) {
        UIFontDescriptor *descriptor = [aDecoder decodeObjectForKey:@"UIFontDescriptor"];

        NSString *fontName;
        if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontRegularUsage"]) {
            fontName = FORegularFontName;
        }
        else if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontEmphasizedUsage"]) {
            fontName = FOBoldFontName;
        }
        else if ([descriptor.fontAttributes[@"NSCTFontUIUsageAttribute"] isEqualToString:@"CTFontObliqueUsage"]) {
            fontName = FOItalicFontName;
        }
        else {
            fontName = descriptor.fontAttributes[@"NSFontNameAttribute"];
        }

        return [UIFont fontWithName:fontName size:descriptor.pointSize];
    }

    self = [self initCustomWithCoder:aDecoder];

    return self;
}

+ (void)load
{
    [self replaceClassSelector:@selector(systemFontOfSize:) withSelector:@selector(regularFontWithSize:)];
    [self replaceClassSelector:@selector(boldSystemFontOfSize:) withSelector:@selector(boldFontWithSize:)];
    [self replaceClassSelector:@selector(italicSystemFontOfSize:) withSelector:@selector(italicFontOfSize:)];

    [self replaceInstanceSelector:@selector(initWithCoder:) withSelector:@selector(initCustomWithCoder:)];
}
#pragma clang diagnostic pop

@end

如何在没有UIFontDescriptor的iOS6上使用此实现? - Utku Yıldırım
我使用了解码器密钥“UIFontTraits”来检查提供的字体是否为粗体或斜体,并用自己的变体替换它。从这里获取 https://gist.github.com/Daij-Djan/5046612。 - Fábio Oliveira
2
感谢@FábioOliveira,它完美地解决了问题!只有一件事情需要注意,你需要在头文件中添加#import <objc/runtime.h>,否则使用'Method'类时会出现错误(我在XCode 6中遇到了这个错误)。 - nahung89
由于某种原因,在iOS 8上,模态框(UIAlertController)不会更改字体。 - Randomblue
@Fábio Oliveira,你的代码更好了。除此之外,请注意如果在你的项目中设置了多种字体类型,并且你只想设置其中一种,那么请将你的这行代码改为:else { fontName =@"yourFontName"; },而不是: else { fontName = descriptor.fontAttributes[@"NSFontNameAttribute"]; } - Ravi
显示剩余2条评论

14

为了补充 Sandy Chapman的回答,这里给出了一个使用Objective-C的解决方案(将这个类别放在你想要更改 UILabel Appearance 的任何地方):

@implementation UILabel (FontOverride)
- (void)setSubstituteFontName:(NSString *)name UI_APPEARANCE_SELECTOR {
    self.font = [UIFont fontWithName:name size:self.font.pointSize];
}
@end
接口文件应该公开声明此方法,以便稍后从诸如您的应用程序委托之类的位置使用:

接口文件应该公开声明此方法,以便稍后从诸如您的应用程序委托之类的位置使用:

@interface UILabel (FontOverride)
  - (void)setSubstituteFontName:(NSString *)name UI_APPEARANCE_SELECTOR;
@end

然后,您可以使用以下方式更改 外观

[[UILabel appearance] setSubstituteFontName:@"SourceSansPro-Light"];

1
你好,你的意思是“任何地方”,那么这段代码就需要添加在每个视图控制器中,而且必须要将每个UILabel都用在控制器中,这样才能改变字体吗? - Jules
不,你必须将这段代码放在你的项目中的任何一个地方,例如在你的_appdelegate_中。 - Damien Debin
1
@DamienDebin 我想使用粗体字来加粗,但这会将粗体变成轻体。有什么解决办法吗? - Zeeshan
实际上,它可以工作,但应该是“类别”还是“扩展”?这里解释了区别:https://dev59.com/1Ww05IYBdhLWcg3wnjAk - Darius Miliauskas

5
我在查看了一些帖子后,为Swift 4创建了自己的排版转换方式,它涵盖了大多数情况,例如:
1. 将字体添加到项目结构和.plist文件中(名称相同):
<key>UIAppFonts</key>
<array>
    <string>Typo-Light.ttf</string>
    <string>Typo-Regular.ttf</string>
    <string>Typo-Semibold.ttf</string>
    <string>Typo-LightItalic.ttf</string>
</array>

那么

struct Resources {

    struct Fonts {
        //struct is extended in Fonts
    }
}

extension Resources.Fonts {

    enum Weight: String {
        case light = "Typo-Light"
        case regular = "Typo-Regular"
        case semibold = "Typo-Semibold"
        case italic = "Typo-LightItalic"
    }
}

extension UIFontDescriptor.AttributeName {
    static let nsctFontUIUsage = UIFontDescriptor.AttributeName(rawValue: "NSCTFontUIUsageAttribute")
}

extension UIFont {

    @objc class func mySystemFont(ofSize: CGFloat, weight: UIFont.Weight) -> UIFont {
        switch weight {
        case .semibold, .bold, .heavy, .black:
            return UIFont(name: Resources.Fonts.Weight.semibold.rawValue, size: ofSize)!

        case .medium, .regular:
            return UIFont(name: Resources.Fonts.Weight.regular.rawValue, size: ofSize)!

        default:
            return UIFont(name: Resources.Fonts.Weight.light.rawValue, size: ofSize)!
        }
    }

    @objc class func mySystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: Resources.Fonts.Weight.light.rawValue, size: size)!
    }

    @objc class func myBoldSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: Resources.Fonts.Weight.semibold.rawValue, size: size)!
    }

    @objc class func myItalicSystemFont(ofSize size: CGFloat) -> UIFont {
        return UIFont(name: Resources.Fonts.Weight.italic.rawValue, size: size)!
    }

    @objc convenience init(myCoder aDecoder: NSCoder) {
        guard
            let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor,
            let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String else {
                self.init(myCoder: aDecoder)
                return
        }
        var fontName = ""
        switch fontAttribute {
        case "CTFontRegularUsage", "CTFontMediumUsage":
            fontName = Resources.Fonts.Weight.regular.rawValue
        case "CTFontEmphasizedUsage", "CTFontBoldUsage", "CTFontSemiboldUsage","CTFontHeavyUsage", "CTFontBlackUsage":
            fontName = Resources.Fonts.Weight.semibold.rawValue
        case "CTFontObliqueUsage":
            fontName = Resources.Fonts.Weight.italic.rawValue
        default:
            fontName = Resources.Fonts.Weight.light.rawValue
        }
        self.init(name: fontName, size: fontDescriptor.pointSize)!
    }

    class func overrideDefaultTypography() {
        guard self == UIFont.self else { return }

        if let systemFontMethodWithWeight = class_getClassMethod(self, #selector(systemFont(ofSize: weight:))),
            let mySystemFontMethodWithWeight = class_getClassMethod(self, #selector(mySystemFont(ofSize: weight:))) {
            method_exchangeImplementations(systemFontMethodWithWeight, mySystemFontMethodWithWeight)
        }

        if let systemFontMethod = class_getClassMethod(self, #selector(systemFont(ofSize:))),
            let mySystemFontMethod = class_getClassMethod(self, #selector(mySystemFont(ofSize:))) {
            method_exchangeImplementations(systemFontMethod, mySystemFontMethod)
        }

        if let boldSystemFontMethod = class_getClassMethod(self, #selector(boldSystemFont(ofSize:))),
            let myBoldSystemFontMethod = class_getClassMethod(self, #selector(myBoldSystemFont(ofSize:))) {
            method_exchangeImplementations(boldSystemFontMethod, myBoldSystemFontMethod)
        }

        if let italicSystemFontMethod = class_getClassMethod(self, #selector(italicSystemFont(ofSize:))),
            let myItalicSystemFontMethod = class_getClassMethod(self, #selector(myItalicSystemFont(ofSize:))) {
            method_exchangeImplementations(italicSystemFontMethod, myItalicSystemFontMethod)
        }

        if let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:))),
            let myInitCoderMethod = class_getInstanceMethod(self, #selector(UIFont.init(myCoder:))) {
            method_exchangeImplementations(initCoderMethod, myInitCoderMethod)
        }
    }
}

最后,在Appdelegate中调用创建的方法,如下所示:

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

        UIFont.overrideDefaultTypography()
        return true
    }
}

@sheshnath,你能给我们提供更多的崩溃信息吗? - Javi AP
1
抱歉,错误是我的问题,字体没有列在info.plist中。 - Sheshnath
@midhunp 你能否更明确一些,以便你的问题不再出现?对我来说,使用粗体字效果很好。 - Javi AP

4

适用于Swift 5

以上所有答案都是正确的,但我按照设备大小的方式进行了一些不同的处理。在ATFontManager类中,我设置了默认字体大小,该大小在类的顶部定义为defaultFontSize,这是iPhone Plus的字体大小,您可以根据自己的要求进行更改。

class ATFontManager: UIFont{
    
    class func setFont( _ iPhone7PlusFontSize: CGFloat? = nil,andFontName fontN : String = FontName.helveticaNeue) -> UIFont{
        
        let defaultFontSize : CGFloat = 16
        
        switch ATDeviceDetector().screenType {
            
        case .iPhone4:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize - 5)!
            }
            return UIFont(name: fontN, size: defaultFontSize - 5)!
            
        case .iPhone5:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize - 3)!
            }
            return UIFont(name: fontN, size: defaultFontSize - 3)!
            
        case .iPhone6AndIphone7, .iPhoneUnknownSmallSize:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize - 2)!
            }
            return UIFont(name: fontN, size: defaultFontSize - 2)!
            
        case .iPhone6PAndIPhone7P, .iPhoneUnknownBigSize:
            
            return UIFont(name: fontN, size: iPhone7PlusFontSize ?? defaultFontSize)!
        case .iPhoneX, .iPhoneXsMax:
            
            return UIFont(name: fontN, size: iPhone7PlusFontSize ?? defaultFontSize)!
          
        case .iPadMini:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize + 2)!
            }
            return UIFont(name: fontN, size: defaultFontSize + 2)!
            
        case .iPadPro10Inch:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize + 4)!
            }
            return UIFont(name: fontN, size: defaultFontSize + 4)!
            
        case .iPadPro:
            if let fontSize = iPhone7PlusFontSize{
                return UIFont(name: fontN, size: fontSize + 6)!
            }
            return UIFont(name: fontN, size: defaultFontSize + 6)!
            
        case .iPadUnknownSmallSize:
            
            return UIFont(name: fontN, size: defaultFontSize + 2)!
            
        case .iPadUnknownBigSize:
            
            return UIFont(name: fontN, size: defaultFontSize + 4)!
            
        default:
            
            return UIFont(name: fontN, size: iPhone7PlusFontSize ?? 16)!
        }
    }
}
     

我已经添加了某个字体名称,如果需要更多,可以在此处添加字体名称和类型。

   enum FontName : String {
        case HelveticaNeue = "HelveticaNeue"
        case HelveticaNeueUltraLight = "HelveticaNeue-UltraLight"
        case HelveticaNeueBold = "HelveticaNeue-Bold"
        case HelveticaNeueBoldItalic = "HelveticaNeue-BoldItalic"
        case HelveticaNeueMedium = "HelveticaNeue-Medium"
        case AvenirBlack = "Avenir-Black"
        case ArialBoldMT = "Arial-BoldMT"
        case HoeflerTextBlack = "HoeflerText-Black"
        case AMCAPEternal = "AMCAPEternal"
    }

这个类是指设备检测器,目的是根据设备提供合适的字体大小。

class ATDeviceDetector {
    
    var iPhone: Bool {
        
        return UIDevice().userInterfaceIdiom == .phone
    }
    
    var ipad : Bool{
        
        return UIDevice().userInterfaceIdiom == .pad
    }
    
    let isRetina = UIScreen.main.scale >= 2.0
    
    
    enum ScreenType: String {
        
        case iPhone4
        case iPhone5
        case iPhone6AndIphone7
        case iPhone6PAndIPhone7P
        case iPhoneX
        
        case iPadMini
        case iPadPro
        case iPadPro10Inch
        
        case iPhoneOrIPadSmallSizeUnknown
        case iPadUnknown
        case unknown
    }
    
    
    struct ScreenSize{
        
        static let SCREEN_WIDTH         = UIScreen.main.bounds.size.width
        static let SCREEN_HEIGHT        = UIScreen.main.bounds.size.height
        static let SCREEN_MAX_LENGTH    = max(ScreenSize.SCREEN_WIDTH,ScreenSize.SCREEN_HEIGHT)
        static let SCREEN_MIN_LENGTH    = min(ScreenSize.SCREEN_WIDTH,ScreenSize.SCREEN_HEIGHT)
    }
    
    
    var screenType: ScreenType {
        
        switch ScreenSize.SCREEN_MAX_LENGTH {
            
        case 0..<568.0:
            return .iPhone4
        case 568.0:
            return .iPhone5
        case 667.0:
            return .iPhone6AndIphone7
        case 736.0:
            return .iPhone6PAndIPhone7P
        case 812.0:
            return .iPhoneX
        case 568.0..<812.0:
            return .iPhoneOrIPadSmallSizeUnknown
        case 1112.0:
            return .iPadPro10Inch
        case 1024.0:
            return .iPadMini
        case 1366.0:
            return .iPadPro
        case 812.0..<1366.0:
            return .iPadUnknown
        default:
            return .unknown
        }
    }
}

如何使用。希望这可以帮助。

//for default 
label.font = ATFontManager.setFont()

//if you want to provide as your demand. Here **iPhone7PlusFontSize** variable is denoted as font size for *iphone 7plus and iphone 6 plus*, and it **ATFontManager** class automatically handle.
label.font = ATFontManager.setFont(iPhone7PlusFontSize: 15, andFontName: FontName.HelveticaNeue.rawValue)

4

针对Swift 3.0和Swift警告的注释

您可以在以下行中删除警告信息:

let initCoderMethod = class_getInstanceMethod(self, Selector("initWithCoder:"))

用以下内容替换它:

let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:)))

哈哈,我不知道Swift可以使用这个。顺便说一下,我会将其更新到上面的答案中。谢谢你,@ucotta! - nahung89

3

这些解决方案并不适用于整个应用程序。我发现在Xcode中帮助管理字体的一件事是以源代码方式打开Storyboard(在文件导航器中控制点击storyboard,然后选择“打开为”>“源代码”),然后进行查找和替换。


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