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

我有一个自定义的字体,我想使用的一切显示文本在我的应用程序,标签,文本视图等。

是否有一种方法来设置整个应用程序的默认字体(标签默认使用 SystemFont) ?

124552 次浏览

也许不会,你可能在你的控件上设置了字体,但是你可以通过集中从哪里获得字体类型来简化这个过程,例如有应用程序委托或其他一些常见的类有一个返回字体的方法,任何需要设置字体的东西都可以调用这个方法,这将有助于在你需要改变你的字体的情况下,你可以在一个地方改变它,而不是在你设置字体的任何地方... 另一种选择可以是你的 UI Element 的子类,它会自动设置字体,但是这可能有点过了。.

在 iOS5中似乎可以使用 UI卖相代理。

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

这将设置字体为您的应用程序中的所有 UILabels 的自定义字体。您需要为每个控件(UIButton、 UILabel 等)重复它。

请记住,您需要将 UIAppFonts 值放在 info.plist 中,并包含包含的字体的名称。

NUI 是 UI卖相代理的替代品。它通过简单地修改样式表,使您可以控制整个应用程序中大量 UI 元素类型的字体(和许多其他属性) ,样式表可以跨多个应用程序重用。

在标签中添加 NUILabel类之后,您可以轻松地控制样式表中的字体:

LabelFontName    String    Helvetica

如果有不同字体大小的标签,可以使用 NUI 的 Label、 LargeLabel 和 SmallLabel 类来控制它们的大小,甚至可以快速创建自己的类。

还有另一个解决方案,它将覆盖 systemFont。

只要创建一个类别

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。

开发从 Hugues BR 的答案,但使用方法旋转我已经到达了一个解决方案,是成功地改变所有的字体,以一个理想的字体在我的应用程序。

你应该在 iOS7中寻找一种动态类型的方法。下面的解决方案不使用 Dynamic Type。


备注:

  • 下面的代码,在其呈现的状态下,从未提交给苹果批准;
  • 有一个更短的版本通过了苹果的提交,也就是没有 - initWithCoder:覆盖。然而,这并不能涵盖所有的情况;
  • 下面的代码出现在一个类中,我用它来设置我的应用程序的样式,该类包含在我的应用程序代理类中,因此可以在任何地方和所有 UIFont 实例中使用;
  • 我在这里使用 Zapfino 只是为了使更多的更改可见;
  • 欢迎您对此代码进行任何改进。

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

另一种方法是在 UIFont 上覆盖 - initWithCoder:方法,以替换任何出现 CTFontRegularUsage的情况以及我的替代方法中的类似情况。 最后一个方法是必要的,因为我发现编码在 NIB 文件中的 UILabel对象不检查 + systemFontWithSize:方法来获取它们的系统字体,而是将它们编码为 UICTFontDescriptor对象。 我曾试图覆盖 - awakeAfterUsingCoder:,但不知怎么的,它被调用的每一个编码对象在我的故事板,并造成崩溃。覆盖 - 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

这些解决方案在整个应用程序中没有一个是普遍适用的。我发现在 Xcode 管理字体的一个方法是打开故事板作为源代码(在文件导航器中控制单击故事板 > “打开作为”> “源”) ,然后执行查找和替换操作。

如果你正在使用 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

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

加法

对于需要分别设置粗体和普通字体的情况:

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

然后为你的 UI 外观代理:

UILabel.appearance().substituteFontName = applicationFont
UILabel.appearance().substituteFontNameBold = applicationFontBold

注意: 如果您发现粗体替换不起作用,那么可能默认的字体名称不包含“ Medium”。根据需要将该字符串切换到另一个匹配(感谢 Mason 在下面的评论中)。

要完成 桑迪 · 查普曼的回答,这里有一个目标 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

然后,你可以改变 Appearance:

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

字体类型总是在代码和 nib/情节串连板中设置。

对于代码,就像 雨果 BR 说一样,做分类就可以解决问题。

对于 nib/Storyboard,我们可以使用 Method Swizzling awakeFromNib 来更改字体类型,因为 nib/Storyboard 的 UI 元素总是在显示在屏幕上之前调用它。

我想你知道 各方面. 它是一个基于方法 Swizzling 的 AOP 编程库。 我们为 UILabel、 UIButton、 UITextView 创建目录来实现它。

乌拉贝尔:

#import "UILabel+OverrideBaseFont.h"
#import "Aspects.h"


@implementation UILabel (OverrideBaseFont)


+ (void)load {
[[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
UILabel* instance = [aspectInfo instance];
UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:instance.font.pointSize];
instance.font = font;
}error:nil];
}


@end

UIButton:

#import "UIButton+OverrideBaseFont.h"
#import "Aspects.h"


@implementation UIButton (OverrideBaseFont)


+ (void)load {
[[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
UIButton* instance = [aspectInfo instance];
UILabel* label = instance.titleLabel;
UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:label.font.pointSize];
instance.titleLabel.font = font;
}error:nil];
}


@end

UITextField:

#import "UITextField+OverrideBaseFont.h"
#import "Aspects.h"


@implementation UITextField (OverrideBaseFont)


+ (void)load {
[[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
UITextField* instance = [aspectInfo instance];
UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:instance.font.pointSize];
instance.font = font;
}error:nil];
}


@end

UITextView:

#import "UITextView+OverrideBaseFont.h"
#import "Aspects.h"


@implementation UITextView (OverrideBaseFont)


+ (void)load {
[[self class]aspect_hookSelector:@selector(awakeFromNib) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
UITextView* instance = [aspectInfo instance];
UIFont* font = [UIFont fontWithName:@"HelveticaNeue-light" size:instance.font.pointSize];
instance.font = font;
}error:nil];
}


@end

这就是全部,你可以改变 HelveticaNeue-light 到一个宏与你的字体名称。

我们在 Swift-Xcode 7.2中使用了父视图控制器和子视图控制器(继承)实现了同样的功能。

文件-新-可可触摸类-ParentViewController。

    import UIKit
import Foundation


class ParentViewController: UIViewController {


var appUIColor:UIColor = UIColor.redColor()
var appFont:UIFont = UIFont(name: "Copperplate", size: 20)!


override func viewDidLoad() {
super.viewDidLoad()
}
func addStatusBar()
{
let view = UIView(frame:
CGRect(x: 0.0, y: 0.0, width: UIScreen.mainScreen().bounds.size.width, height: 20.0)
)
view.backgroundColor = appUIColor
self.view.addSubview(view)
}
}

创建子视图控制器并与 StoryBoard VC 关联,添加 textLabel。

    import UIKit


class FontTestController: ParentViewController {
@IBOutlet var testLabel: UILabel!


override func viewDidLoad() {
super.viewDidLoad()
testLabel.font =  appFont
testLabel.textColor = appUIColor
}

或创建一个自定义 UILabel 类(Sub 分类方法)并将所需的标签与之关联。

import Foundation
import UIKit


class CustomFontLabel: UILabel {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
backgroundColor = ParentViewController().appUIColor
font = ParentViewController().appFont
textColor = UIColor.blackColor()
}
}

注意: 在父 VC 中声明的字体和颜色在 CustomFontLabel 中实现。这样做的好处是我们可以在 Parent VC 中通过一些简单的改变来改变 uilabel/any 视图的所有属性。

2)‘ for’循环 UIView 用于子视图。它只能在特定的 VC 上运行。

    override func viewWillLayoutSubviews() {
for view in self.view.subviews  {
if view.isKindOfClass(UITextField) {
UITextField.appearance().font =  UIFont(name: "Copperplate", size: 20)
}
if view.isKindOfClass(UILabel) {
UILabel.appearance().font =  UIFont(name: "Copperplate", size: 20)
}
}
}

Swift 5

基于法比奥 · 奥利维拉的回答(https://stackoverflow.com/a/23042694/2082851) ,我做出了自己的迅捷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()
}
...
}

对 SWIFT 3.0和 SWIFT 警告的评论

您可以删除一行中的警告消息:

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

将其替换为:

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

为了 Swift 5

以上所有的答案都是正确的,但我已经做了一些不同的方式,这是 根据设备大小。 在这里,在 ATFontManager 类中,我设置了默认的字体大小,在类的顶部定义为 默认字号,这是 Iphone + ,你可以根据你的要求进行更改。

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)

我使用类似这种类型的字体类在迅速。使用字体扩展类。

enum FontName: String {


case regular      = "Roboto-Regular"


}


//MARK: - Set Font Size
enum FontSize: CGFloat {
case size = 10


}
extension UIFont {


//MARK: - Bold Font
class var regularFont10: UIFont {
return UIFont(name: FontName.regular.rawValue, size:FontSize.size.rawValue )!
}
}

对于 Appgenerate 的 FinishedLaunching()中的 Xamarin.iOS,将代码放置如下:-

UILabel.Appearance.Font= UIFont.FromName("Lato-Regular", 14);

为整个应用程序设置字体并在 Info.plist 上添加‘ UIAppFonts’键,路径应该是您的字体文件所在的路径。TTF 位于。对我来说,它是在我的项目中的“字体”文件夹。

<key>UIAppFonts</key>
<array>
<string>fonts/Lato-Regular.ttf</string>
</array>

在回顾了几篇文章之后,我为 Swift 4创建了自己的字体转换,它涵盖了大多数情况,比如:

第一步为项目结构和.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调用 create 方法,如下所示:

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


UIFont.overrideDefaultTypography()
return true
}
}

正如 @ Randall在他的 回答中提到的 iOS 5.0 + UIAppearance代理可以用来定制类 继续读的所有实例的外观。

UILabel.appearance().font = .systemFont(ofSize: 17, weight: .regular)