[ios] 전체 iOS 앱에 기본 글꼴을 설정 하시겠습니까?

앱의 텍스트, 레이블, 텍스트보기 등을 표시하는 모든 것에 사용하려는 사용자 정의 글꼴이 있습니다.

전체 앱에 기본 글꼴 (기본적으로 레이블은 SystemFont를 사용함)을 설정하는 방법이 있습니까?



답변

iOSAppearance 프록시를 사용하는 iOS 5에서 가능합니다.

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

그러면 글꼴이 앱의 모든 UILabels에 대한 사용자 정의 글꼴이되도록 설정됩니다. 각 컨트롤 (UIButton, UILabel 등)에 대해 반복해야합니다.

info.plist에 UIAppFonts 값을 입력하고 포함하는 글꼴 이름을 포함해야합니다.


답변

스위프트 5

Fábio Oliveira의 답변 ( 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()
    }
    ...
}


답변

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

이것은 기본 구현을 대체하며 대부분의 UIControl은 systemFont를 사용합니다.


답변

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_SELECTORname 속성을 사용하는 동등한 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에게 감사드립니다).


답변

Hugues BR 답변에서 개발했지만 방법 스위 즐링을 사용하여 모든 글꼴을 내 앱에서 원하는 글꼴로 성공적으로 변경하는 솔루션에 도달했습니다.

동적 유형을 사용하는 접근 방식은 iOS 7에서 찾아야합니다. 다음 솔루션은 동적 유형을 사용하지 않습니다.


노트:

  • 아래 코드는 제시된 상태에서 Apple의 승인을받지 못했습니다.
  • Apple 제출을 통과 한 더 짧은 버전이 - initWithCoder:있습니다. 즉, 재정의 가 없습니다 . 그러나 모든 경우를 다루지는 않습니다.
  • 다음 코드는 AppDelegate 클래스에 포함 된 내 앱의 스타일을 설정하는 데 사용하는 클래스에 있으며 모든 UIFont 인스턴스에서 사용할 수 있습니다.
  • 여기에서 Zapfino를 사용하여 변경 사항을 훨씬 더 눈에 띄게 만듭니다.
  • 이 코드에 대한 개선 사항은 언제든지 환영합니다.

이 솔루션은 두 가지 방법으로 최종 결과를 얻습니다. 첫 번째는 UIFont 클래스 메소드를 대체하고 대체 방법 + systemFontWithSize:을 사용하는 메소드 와 유사합니다 (여기서는 “Zapfino”를 사용하여 교체가 성공했는지 의심하지 않습니다).

다른 방법은 - initWithCoder:UIFont의 메서드 를 재정 CTFontRegularUsage의하여 내 대안으로 발생 하고 유사한 것을 대체하는 것입니다. 이 마지막 방법은 UILabelNIB 파일로 인코딩 된 객체 + 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


답변

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


답변

SWIFT 3.0 및 SWIFT 경고에 대한 설명

다음과 같은 경고 메시지를 제거 할 수 있습니다.

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

다음과 같이 바꾸면됩니다 :

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