앱의 텍스트, 레이블, 텍스트보기 등을 표시하는 모든 것에 사용하려는 사용자 정의 글꼴이 있습니다.
전체 앱에 기본 글꼴 (기본적으로 레이블은 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_SELECTOR
name 속성을 사용하는 동등한 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
의하여 내 대안으로 발생 하고 유사한 것을 대체하는 것입니다. 이 마지막 방법은 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
답변
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:)))