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

Sam*_*man 151 fonts ios

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

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

Ran*_*all 157

在iOS 5中似乎可以使用UIAppearance代理.

 [[UILabel appearance] setFont:[UIFont fontWithName:@"YourFontName" size:17.0]];
Run Code Online (Sandbox Code Playgroud)

这会将字体设置为应用中所有UILabel的自定义字体.你需要为每个控件(UIButton,UILabel等)重复它.

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

  • 谢谢你的回复.我能够让这个工作.你知道是否有办法指定字体而不指定字体大小?我的应用程序中的标签不具有相同的字体大小. (44认同)
  • 我是否可以在不覆盖每个实例的磅值的情况下执行此操作? (22认同)
  • `setFont:`方法已被弃用 (17认同)
  • @Anand你确定吗?我没有看到它在'UILabel`中被标记为已弃用.它不推荐用于`UIButton`,但它使用`titleLabel`属性的字体而不是`UILabel`,所以只需使用`UILabel`的外观代理设置字体应该没问题. (12认同)
  • @Anand UILabel不推荐使用它. (6认同)
  • 文档很清楚,_font_属性UILabel不会被弃用.如果你收到警告,那是因为+外观返回_id_而XCode可能正在查找错误的基类(例如UITableViewCell).http://developer.apple.com/library/ios/documentation/uikit/reference/UILabel_Class/Reference/UILabel.html#//apple_ref/occ/instp/UILabel/font (3认同)
  • 为了保持字体,也许这会有所帮助:`[[UILabel外观] setFont:[UIFont fontWithName:@"YourFontName"size:[UILabel外观] .font.pointSize]]; (3认同)

nah*_*g89 98

Swift 4.1

根据FábioOliveira的回答(/sf/answers/1612988611/),我制作了自己的快速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 {

    @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 else { return }

        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()
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 最佳答案!!自动覆盖系统字体,精彩纷呈 (2认同)
  • 如果有人对"NSCTFontUIUsageAttribute"行有问题:`如果让fontAttribute = fontDescriptor.fontAttributes [.nsctFontUIUsage]为?String {`为我做了诀窍. (2认同)

Hug*_* BR 74

还有另一种解决方案是覆盖systemFont.

只需创建一个类别

UIFont + SystemFontOverride.h

#import <UIKit/UIKit.h>

@interface UIFont (SystemFontOverride)
@end
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这将取代默认实现,大多数UIControl使用systemFont.

  • 当一个类别的方法具有与它所扩展的类相同的签名时,行为是未定义的.要替换类方法,您应该使用方法调配(这也不是一个好主意). (4认同)
  • 这可以.Apple只是不希望您使用未记录的功能.你被允许"混合"公开的方法. (2认同)

San*_*man 60

如果您使用的是Swift,则可以创建UILabel扩展:

extension UILabel {

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

}
Run Code Online (Sandbox Code Playgroud)

然后你在哪里做你的外观代理:

UILabel.appearance().substituteFontName = applicationFont
Run Code Online (Sandbox Code Playgroud)

UI_APPEARANCE_SELECTOR具有名称的属性上使用等效的Objective-C代码substituteFontName.

加成

对于您想要分别设置粗体和常规字体的情况:

extension UILabel {

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

    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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后为您的UIAppearance代理:

UILabel.appearance().substituteFontName = applicationFont
UILabel.appearance().substituteFontNameBold = applicationFontBold
Run Code Online (Sandbox Code Playgroud)

注意:如果您发现粗体替换不起作用,则默认字体名称可能不包含"中".根据需要将该字符串切换为另一场比赛(感谢Mason在下面的评论中).

  • @MasonG.Zhwiti在这种情况下,我可能会设置`UILabel`扩展名,以便为粗体添加一个额外的字体名称.然后在`set`中检查字体名称中是否有"Bold"并在一种情况下忽略该集合,并在另一种情况下使用它.我将编辑并添加一个示例. (2认同)
  • @SandyChapman我弄清楚发生了什么.iOS 8的默认字体往往是HelveticaNeueInterface-Regular或(粗体)HelveticaNeueInterface-MediumP4.所以寻找"大胆"从未与任何东西相匹配.我将它改为`rangeOfString("Medium")`并且它有效. (2认同)

Fáb*_*ira 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
Run Code Online (Sandbox Code Playgroud)

  • 谢谢@FábioOliveira,它就像一个魅力!还有一件事你需要将#import <objc/runtime.h>放在标题上,否则你会因使用'Method'类而得到错误(我在XCode 6中得到的错误) (2认同)

Dam*_*bin 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
Run Code Online (Sandbox Code Playgroud)

接口文件应该公开声明此方法,以便稍后从app delegate这样的地方使用:

@interface UILabel (FontOverride)
  - (void)setSubstituteFontName:(NSString *)name UI_APPEARANCE_SELECTOR;
@end
Run Code Online (Sandbox Code Playgroud)

然后,您可以更改Appearance:

[[UILabel appearance] setSubstituteFontName:@"SourceSansPro-Light"];
Run Code Online (Sandbox Code Playgroud)


Jav*_*nas 5

在查看了一些帖子后,我为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>
Run Code Online (Sandbox Code Playgroud)

然后

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后调用 created 方法Appdelegate如下:

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

        UIFont.overrideDefaultTypography()
        return true
    }
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

96938 次

最近记录:

6 年,8 月 前