본문 바로가기

iOS

[iOS] 앱 내 기본글꼴 커스텀 폰트로 설정하기

 이번 사이드프로젝트에는 상당히 많은 걸 시도하고 노력하고 있는데요,

그 중 공유할만한 수확물을 소개하려 합니다. 오늘 소개할 것은 글꼴에 관련한 것입니다.

개발자님 마다 폰트를 다루는 방법이 다양하고 각각 다른데요, 더 좋은 방법이 있다면 알려주시면 감사하겠습니다.(__)

 

우선, 먼저 커스텀 폰트를 적용하는 방법을 간단하게 소개하고 진행하겠습니다!

1. 프로젝트 내에 폰트 복사하고 TargetMembership 설정하기

스포카한산즈체를 적용하고자 합니다. 토스에서 사용하는 고딕체입니다.

사용하고자 하는 폰트를 모두 클릭 후 타겟멤버십에 체크해줍니다.

 

2. info.plist file 수정하기

Font provided by application을 추가한 후

폰트 이름 뒤 .ttf까지 깔끔하게 추가해 줍니다.  다음과 같이 폰트를 설정해 줄 수 있게 됩니다.

 

(1) 스토리보드에서 폰트를 설정해주거나,

(2)

anyLabel.font = UIFont(name: "customfont", size: "17")

위 두 가지 방법으로 보통 많이 사용하는데요,

 

아래 방법은 시스템 폰트를 원하는 커스텀 폰트로 바꿀 수 있게 됩니다. 


struct AppFontName {
    static let regular = "SpoqaHanSans"
    static let bold = "SpoqaHanSans-Bold"
    static let italic = "SpoqaHanSans-Light"
}

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) {
        if let fontDescriptor = aDecoder.decodeObject(forKey: "UIFontDescriptor") as? UIFontDescriptor {
            if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String {
                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)!
            }
            else {
                self.init(myCoder: aDecoder)
            }
        }
        else {
            self.init(myCoder: aDecoder)
        }
    }

     class func overrideInitialize() {
        if self == UIFont.self {
           let systemFontMethod = class_getClassMethod(self, #selector(systemFont(ofSize:)))
           let mySystemFontMethod = class_getClassMethod(self, #selector(mySystemFont(ofSize:)))
           method_exchangeImplementations(systemFontMethod!, mySystemFontMethod!)

           let boldSystemFontMethod = class_getClassMethod(self, #selector(boldSystemFont(ofSize:)))
           let myBoldSystemFontMethod = class_getClassMethod(self, #selector(myBoldSystemFont(ofSize:)))
           method_exchangeImplementations(boldSystemFontMethod!, myBoldSystemFontMethod!)

           let italicSystemFontMethod = class_getClassMethod(self, #selector(italicSystemFont(ofSize:)))
           let myItalicSystemFontMethod = class_getClassMethod(self, #selector(myItalicSystemFont(ofSize:)))
           method_exchangeImplementations(italicSystemFontMethod!, myItalicSystemFontMethod!)

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

 

코드 설명을 해 보겠습니다!

UIFont.systemfont(ofSize: ~)
UIFont.boldSystemfont(ofSize: ~)
UIFont.italicSystemfont(ofSize: ~)

기본적으로, 위와 같은 기본 UIFont 내장함수를 변경하는 일입니다.

 

systemfont(ofSize: ~) < > mySystemFont(ofSize:~)
boldSystemfont(ofSize: ~) <> myBoldSystemfont(ofSize: ~)

italicSystemfont(ofSize: ~) <> myItalicSystemfont(ofSize: ~)

 

위에서는 지정하고자 하는 폰트를 각각 원하는 위치의 Struct에 위치시키고,

convenience init(~)

을 통해 원하는 파라미터만 변경한 후 이니셜라이징 해 줍니다.

 

폰트가 만들어질 때 호출되는 함수가 달라지게 됩니다. 기본적인 세가지 시스템 함수를 변경해주었습니다.

다르게 추가하는 방법도 있는데, 숙지하게 되면 다시 적겠습니다!

 

이후, AppDelegate에서

    override init() {
        super.init()
        UIFont.overrideInitialize()
    }

적용시켜주면 완성되게 됩니다. 실행 사진은 다음과 같습니다.

 

 

왼쪽 : 변경 전, 오른쪽 : 변경 후

아니 잘 보이지 않으니까,,,몇개를 또 찍어보겠습니다...(억울) 사실 티 많이 납니다

 

왼쪽 : 이전 ///// 오른쪽 : 적용 이후

이건 티가 좀 나네요. 왼쪽은 디폴트 시스템폰트, 오른쪽은 스포카한산즈 입니다!

질문이나 오류가 있다면 댓글 달아주시면 감사하겠습니다.

 

StackOverflow, https://stackoverflow.com/questions/46404557/changing-all-uilabel-fonts-in-app-depending-on-current-font-weight-using-swift-4