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


155

我有一个自定义字体,我希望将其用于在应用程序,标签,文本视图等中显示文本的所有内容。

有没有办法为整个应用程序设置默认字体(默认情况下,标签使用SystemFont)?


7
大规模地研究了这一祸患。老实说,我们发现要做的最简单的事情就是为每个控件创建一个(简单的)新类。因此,对于UIButton,请创建SJButton。不要忘记同时覆盖initWithFrame和initWithCode。为每个控件(例如UIButton等)设置颜色或您喜欢的任何颜色。仔细挑选int代码中的大小(即将是故事板上的大小),然后(根据您的喜好)使用该大小(并设置字体,颜色等)。它只有几行代码,非常整洁,从长远来看可以节省大量时间。
Fattie

@JoeBlow感谢张贴您的发现-大约要花费时间去寻找答案,以我自己
JJ。

@ jj-对。也不要忘记,IBDesignable这些天您肯定必须使用。希望能帮助到你。还请考虑以下有趣的质量检查:stackoverflow.com/a/38000466/294884
Fattie

Answers:


158

在iOS 5中,使用UIAppearance代理似乎是可能的。

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

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

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


46
感谢您的回复。我能够使它工作。您是否知道是否可以指定字体而不指定字体大小?我的应用程序中有一些标签,它们的字体大小不相同。
布兰登

23
我可以这样做而不覆盖每个实例的点大小吗?
Michael Forrest

17
setFont:方法已弃用
Anand 2012年

12
@Anand你确定吗?我看不到标记为已弃用UILabel。不UIButton建议使用它,但它使用titleLabel属性的字体代替UILabel,所以只需使用外观代理设置字体就UILabel可以了。
AdrianSchönig'13

6
@Anand不推荐使用UILabel。
Alastair Stuart

118

斯威夫特5

基于FábioOliveira的答案(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()
    }
    ...
}

2
最佳答案!!自动覆盖系统字体,精彩
Kappe

2
如果有人对“ NSCTFontUIUsageAttribute”这一行有疑问,那就if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String {帮我吧。
知识

1
似乎不适UILabel用于设置文本样式(粗体,标题,标题等)的s ...仅适用于具有特定大小和系统字体集的字体。@ nahung89
aviran

1
这也会切换某些系统UI字体。例如,键盘建议列表和操作表。不知道这是否会导致苹果拒绝该应用程序
亨利·H·苗

1
此答案发布已经一年了。有没有人能以更“原生”的苹果方式实现这一目标?
格雷格·希尔斯顿

75

还有另一个解决方案将是覆盖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。


1
这是否符合Apple准则?
Rambatino

这更像是一个hack。我没有使用此黑客添加我的应用程序注册,因为它没有使用任何私有方法。如果您想要一个更强大的解决方案,我也建议您检查一下:github.com/0xced/FontReplacer
Hugues BR

2
这可以。Apple只是不希望您使用未记录的功能。您可以“麻烦”公开的方法。
mxcl 2014年

4
当类别具有与类具有相同签名的方法时,其行为是不确定的。要替换类方法,您应该使用方法混乱(这也不是一个好主意)。
GreatWiz 2014年

1
正如其他人所指出的那样,尽管该解决方案在大多数情况下可能会很有效,但从技术上讲却引入了不确定行为的可能性。如果您不想冒险,方法混用可能是一个更好的选择。答案在这里提供了通过混写相同的解决方案:stackoverflow.com/questions/19542942/...
弥敦道Hosselton

63

如果您使用的是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

UI_APPEARANCE_SELECTOR在名称为的属性上使用了等效的Objective-C代码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

注意:如果发现粗体替换无效,则默认字体名称可能不包含“中”。根据需要将字符串切换为另一个匹配项(感谢下面的注释中的Mason)。


我发现的一个缺点是,当我使用UIAlertController启动警报时,具有.Cancel样式的按钮与具有.Default样式的按钮相同(至少在使用GillSans时)。通常,.Cancel是常规粗体字体,而.Default将是粗体。有任何想法吗?
Mason G. Zhwiti 2015年

抱歉,我的意思是。取消标签通常为粗体,默认标签通常为常规粗细。
Mason G. Zhwiti 2015年

2
@ MasonG.Zhwiti在这种情况下,我可能会设置UILabel扩展名以使用其他字体名称来显示粗体。然后,set在字体名称中检查“粗体”是否存在,在一种情况下忽略该设置,在另一种情况下使用它。我将编辑并添加一个示例。
桑迪·查普曼

@SandyChapman谢谢!我正在尝试这项新技术,这很有意义,但它似乎对我没有用。我在iOS 8.3模拟器上使用GillSans和GillSans-Bold。你测试过这项技术了吗?
Mason G. Zhwiti 2015年

2
@SandyChapman我知道发生了什么事。iOS 8的默认字体通常为HelveticaNeueInterface-Regular或(加粗)HelveticaNeueInterface-MediumP4。因此,寻找“ Bold”从来没有匹配任何东西。我将其更改为rangeOfString("Medium"),并且有效。
Mason G. Zhwiti 2015年

23

从Hugues BR答案开发,但是使用方法混淆,我已经找到了一种解决方案,可以成功将所有字体更改为我的应用程序中所需的字体。

您应该在iOS 7上使用动态类型方法。以下解决方案未使用动态类型。


笔记:

  • 以下代码处于其呈示状态,从未提交给Apple批准;
  • 有一个简短的版本通过了Apple提交,但没有- initWithCoder:覆盖。但是,这并不涵盖所有情况。
  • 我用来设置App样式的类中包含以下代码,该样式包含在AppDelegate类中,因此可在所有地方以及所有UIFont实例中使​​用;
  • 我在这里使用Zapfino只是为了使更改更明显。
  • 欢迎您对此代码进行任何改进。

该解决方案使用两种不同的方法来获得最终结果。第一个是重写UIFont类方法,+ systemFontWithSize:并且与使用我的替代方法的方法类似(此处使用“ Zapfino”毫无疑问,替换成功)。

另一种方法是重写- initWithCoder:UIFont上的方法,以用CTFontRegularUsage我的替代方法替换出现的任何类似事件。最后一种方法是必需的,因为我发现UILabel用NIB文件编码的对象不会检查+ 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

您如何在没有UIFontDescriptor的iOS6上使用此实现
UtkuYıldırım

我使用了解码器键“ UIFontTraits”来检查提供的字体是粗体还是斜体,并用我自己的变体替换它。在这里gist.github.com/Daij-Djan/5046612从此要点中获得了它。
法比奥·奥利维拉

感谢您的回答,我现在使用了另一个解决方案。当我再次需要它时,我会检查它:)
UtkuYıldırım2014年

2
感谢@FábioOliveira,它就像一个魅力!您只需要在标头上添加#import <objc / runtime.h>即可,否则,将通过使用'Method'类(我在XCode 6中遇到错误)而
报错

由于某些原因,在iOS 8上,模式(UIAlertController)不会更改字体。
Randomblue

13

为了完成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

然后,您可以使用更改Appearance

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

1
嗨,您是说“随处可见”,必须在每个视图控制器中添加该代码,并在控制器中使用每个UILabel来更改字体吗?
Jules

不,您必须在项目中的任何地方放置一次此代码;例如在您的appdelegate中。
Damien Debin 2015年

1
@DamienDebin我想使用粗体显示粗体,但这会将粗体更改为浅色。可以吗
Zeeshan 2015年

确实可以,但是应该是“类别”还是“扩展”?所不同的解释在这里:stackoverflow.com/questions/7136124/...
大流士Miliauskas

4

SWIFT 3.0和SWIFT警告的评论

您可以删除以下警告消息:

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

通过将其替换为:

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

大声笑。我不知道Swift允许使用它。顺便说一句,我将其更新为以上答案。谢谢@ucotta!
nahung89'4

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)

3

这些解决方案均无法在整个应用程序中通用。我发现可以帮助管理Xcode中的字体的一件事是将情节提要板作为源代码打开(在文件导航器中,按住Control键并单击情节提要板>“另存为”>“源代码”),然后进行查找和替换。


3

字体类型总是在代码和笔尖/故事板上设置。

对于代码,就像Hugues BR所说的那样,在类别中执行它可以解决问题。

对于笔尖/故事板,我们可以使用方法Swizzling awakeFromNib更改字体类型,因为笔尖/故事板的UI元素始终在屏幕上显示之前调用它。

我想您知道Aspects。这是一个基于Method Swizzling的AOP编程库。我们为UILabel,UIButton,UITextView创建类别以实现它。

UILabel:

#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更改为宏。


3

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

1st将字体添加到项目结构和.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您可以给我们更多崩溃信息吗?
哈维尔·阿莫尔·佩纳斯

1
遗憾的错误是从我的身边,字体不是在info.plist中列出
shesh纳特

@midhunp您能否更明确地说明它对您不起作用?粗体字对我来说效果很好。
哈维尔·阿莫尔·佩纳斯

2

可能不是,您可能会自己在控件上设置字体,但是您可以通过集中从哪里获取字体类型来简化此过程,例如让应用程序委托或某些其他公共类拥有返回该字体的方法。字体,任何需要设置字体的方法都可以调用该方法,这将在您需要更改字体的情况下提供帮助,您可以在一个位置而不是在设置字体的任何地方进行更改...另一种选择可以是使您的UI元素,该元素将自动设置字体,但可能会过大。


记录下来,这就是我所做的,但是@Randall需要代表,并提供了一个很好的答案。我只需要支持不到5.0的标准
Sam Jarman'1

4
我不同意你的所作所为。当您的问题被标记为iphone-sdk-4.0时,您选择的答案无效。
Paulo Casaretto,2012年

@Sam Jarman,Randall在下面的回答是正确的-您可以为以后的访客标记吗?
法案

1

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

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

LabelFontName    String    Helvetica

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


1

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

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

0

对于AppDelegate的FinishedLaunching()put代码中的Xamarin.iOS,如下所示:-

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

设置整个应用程序的字体并UIAppFonts在Info.plist上添加' '键,该路径应为您的字体文件.ttf所在的路径。对我而言,该路径位于项目的'fonts'文件夹中。

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

0

作为@Randall提到的iOS 5.0及UIApperance代理可以用来定制的所有实例的外观的类阅读更多

Xcodes自动完成功能不会显示所有可用的属性,并且可能会引发错误,但是您可以键入它并进行编译。

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

-1

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

文件-新建-Cocoa Touch类-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类(子分类方法),并将所需的标签与其关联。

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

注意:Parent VC中声明的Font和color在CustomFontLabel中实现。优点是我们可以通过对父VC进行一些简单更改来一起更改uilabel /任何视图的属性。

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)    
                }               
            }       
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.