Ustawić domyślną czcionkę dla całej aplikacji na iOS?


155

Mam niestandardową czcionkę, której chcę używać do wszystkiego, co wyświetla tekst w mojej aplikacji, etykiety, widoki tekstu itp.

Czy istnieje sposób na ustawienie domyślnej czcionki (etykiety domyślnie używają czcionek SystemFont) dla całej aplikacji?


7
Po masowym przyjrzeniu się temu nieszczęściu. Szczerze mówiąc, odkryliśmy, że najprostszą rzeczą do zrobienia jest utworzenie (trywialnej) nowej klasy dla każdej kontrolki. Więc dla UIButton, zrób SJButton. Nie zapomnij zastąpić zarówno initWithFrame, jak i initWithCode. Dla każdego elementu sterującego (np. UIButton itp.) Ustaw kolory lub cokolwiek chcesz. Ostrożnie podnieś, powiedz rozmiar (tj. Będzie to rozmiar USTAWIONY NA STORYBOARDZIE) w kodzie int, a następnie (jak wolisz) użyj tego rozmiaru (i ustaw, powiedzmy, czcionkę, kolor - cokolwiek). To tylko kilka linijek kodu, jest niesamowicie uporządkowany i na dłuższą metę pozwala zaoszczędzić ogromną ilość czasu.
Fattie

@JoeBlow Dzięki za opublikowanie swoich ustaleń - miałem zamiar spędzić czas, szukając odpowiedzi na to pytanie
jj.

@ jj- Racja. Nie zapomnij też, że z pewnością MUSISZ używać w IBDesignabledzisiejszych czasach. Mam nadzieję, że to pomoże.
Weź

Odpowiedzi:


158

Wydaje się, że jest to możliwe w iOS 5 przy użyciu proxy UIAppearance.

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

Spowoduje to ustawienie czcionki na dowolną niestandardową czcionkę dla wszystkich etykiet UIL w Twojej aplikacji. Będziesz musiał powtórzyć to dla każdej kontrolki (UIButton, UILabel itp.).

Pamiętaj, że musisz umieścić wartość UIAppFonts w swoim info.plist i podać nazwę dołączonej czcionki.


46
Dzięki za odpowiedzi. Udało mi się to uruchomić. Czy wiesz, czy istnieje sposób określenia czcionki bez określania rozmiaru czcionki? Mam etykiety w mojej aplikacji, które nie mają tego samego rozmiaru czcionki.
Brandon

23
Czy mogę to zrobić bez zastępowania rozmiaru punktu w każdym wystąpieniu?
Michael Forrest

17
setFont:metoda jest przestarzała
Anand

12
@Anand czy jesteś tego pewien? Nie widzę tego w programie jako przestarzałe UILabel. Jest przestarzały, UIButtonale używa czcionki titleLabelzamiast a UILabel, więc samo ustawienie czcionki z proxy wyglądu UILabelpowinno wystarczyć.
Adrian Schönig

6
@Anand nie jest przestarzały dla UILabel.
Alastair Stuart

118

Szybki 5

Bazując na odpowiedzi Fábio Oliveiry ( https://stackoverflow.com/a/23042694/2082851 ), tworzę własny szybki 4.

W skrócie, to wymiana domyślne rozszerzenie funkcji init(coder:), systemFont(ofSize:), boldSystemFont(ofSize:), italicSystemFont(ofSize:)z moich metod niestandardowych.

Zauważ, że nie jest w pełni zaimplementowany, ale możesz wymienić więcej metod na podstawie mojej implementacji.

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
najlepsza odpowiedź!! automatycznie zastępuje czcionkę systemową, genialnie
Kappe

2
Jeśli ktoś ma problemy z linią „NSCTFontUIUsageAttribute”: załatwił sprawę if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String {za mnie.
Wiedza

1
wydaje się, że nie działa z UILabels, które ustawiają styl tekstu (pogrubienie, nagłówek, tytuł itp.) ... działa tylko z czcionkami o określonym rozmiarze i ustawionych czcionkach systemowych. @ nahung89
aviran

1
Spowoduje to również zmianę niektórych czcionek interfejsu użytkownika systemu. Na przykład lista sugestii dotyczących klawiatury i arkusz działań. Nie wiem, czy spowoduje to odrzucenie aplikacji przez Apple
Henry H Miao

1
Minął rok od opublikowania tej odpowiedzi. Czy ktoś ma bardziej „natywny” sposób Apple, aby to osiągnąć?
Greg Hilston

75

Jest też inne rozwiązanie, które będzie polegało na nadpisaniu systemFont.

Po prostu utwórz kategorię

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

Spowoduje to zastąpienie domyślnej implementacji i większość kontrolek UIControl używa systemFont.


1
Czy mieści się to w wytycznych Apple?
Rambatino

To bardziej hack. Nie dodałem rejestru mojej aplikacji za pomocą tego hacka, ponieważ nie używa żadnych prywatnych metod. Jeśli chcesz bardziej niezawodnego rozwiązania, sugeruję również sprawdzenie tego: github.com/0xced/FontReplacer
Hugues BR

2
Jest okej. Apple po prostu nie chce, abyś używał nieudokumentowanych funkcji. Możesz zmieniać metody, które są publiczne.
mxcl,

4
Gdy kategoria ma metody z taką samą sygnaturą jak klasa, która rozszerza, zachowanie jest niezdefiniowane. Aby zamienić metody klas, powinieneś użyć swizzling metod (co również nie jest dobrym pomysłem).
GreatWiz

1
Jak zauważyli inni, to rozwiązanie, choć prawdopodobnie będzie skuteczne przez większość czasu, z technicznego punktu widzenia wprowadza potencjał niezdefiniowanego zachowania. Jeśli nie masz ochoty ryzykować, lepszym rozwiązaniem może być zamiana metod. Odpowiedź tutaj zapewnia to samo rozwiązanie poprzez swizzling: stackoverflow.com/questions/19542942/…
Nathan Hosselton

63

Jeśli używasz języka Swift, możesz utworzyć rozszerzenie UILabel:

extension UILabel {

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

}

A potem, gdzie robisz swój wygląd proxy:

UILabel.appearance().substituteFontName = applicationFont

Istnieje równoważny kod Objective-C używający UI_APPEARANCE_SELECTORwłaściwości o nazwie substituteFontName.

Dodanie

W przypadku, gdy chcesz osobno ustawić pogrubione i zwykłe czcionki:

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

Następnie dla serwerów proxy UIAppearance:

UILabel.appearance().substituteFontName = applicationFont
UILabel.appearance().substituteFontNameBold = applicationFontBold

Uwaga: jeśli stwierdzisz, że pogrubienie nie działa, możliwe, że domyślna nazwa czcionki nie zawiera słowa „Medium”. W razie potrzeby wyłącz ten ciąg na inny mecz (dzięki Masonowi w komentarzach poniżej).


Jedną z wad tego rozwiązania jest to, że kiedy inicjuję alerty za pomocą UIAlertController, przycisk ze stylem .Cancel jest taki sam jak przycisk ze stylem .Default (przynajmniej w przypadku używania GillSans). Podczas gdy normalnie .Cancel byłoby czcionką o zwykłej grubości, a .Default byłoby pogrubione. Jakieś pomysły?
Mason G. Zhwiti

Przykro mi, chodziło mi o. Anuluj etykiety normalnie byłyby pogrubione, a Domyślne zwykle miałyby normalną wagę.
Mason G. Zhwiti

2
@ MasonG.Zhwiti W takim przypadku prawdopodobnie skonfigurowałbym UILabelrozszerzenie tak, aby przyjmowało dodatkową nazwę czcionki dla pogrubienia. Następnie setsprawdź, czy w nazwie czcionki jest „Pogrubiona” i zignoruj ​​zestaw w jednym przypadku, a użyj go w drugim. Zmienię i dodam przykład.
Sandy Chapman

@SandyChapman Thanks! Próbuję tej nowej techniki i ma to sens, ale wydaje mi się, że nie działa. Używam GillSans i GillSans-Bold na symulatorze iOS 8.3. Czy przetestowałeś tę technikę?
Mason G. Zhwiti

2
@SandyChapman Zorientowałem się, co się dzieje. Domyślnymi czcionkami dla iOS 8 są zazwyczaj HelveticaNeueInterface-Regular lub (dla pogrubienia) HelveticaNeueInterface-MediumP4. Więc szukanie „Bold” nigdy nie pasowało do niczego. Zmieniłem to na rangeOfString("Medium")i zadziałało.
Mason G. Zhwiti

23

Opracowując z odpowiedzi Hugues BR, ale używając swizzling metody, doszedłem do rozwiązania, które z powodzeniem zmienia wszystkie czcionki na żądaną czcionkę w mojej aplikacji.

Podejście z typem dynamicznym powinno być tym, czego powinieneś szukać w systemie iOS 7. Poniższe rozwiązanie nie używa typu dynamicznego.


Uwagi:

  • poniższy kod, w przedstawionym stanie, nigdy nie został przedłożony do zatwierdzenia przez Apple;
  • istnieje jego krótsza wersja, która przeszła przez zgłoszenie Apple, czyli bez - initWithCoder:nadpisania. Jednak to nie obejmie wszystkich przypadków;
  • następujący kod jest obecny w klasie, której używam do ustawiania stylu mojej aplikacji, która jest zawarta w mojej klasie AppDelegate, dzięki czemu jest dostępna wszędzie i dla wszystkich instancji UIFont;
  • Używam Zapfino tylko po to, aby zmiany były bardziej widoczne;
  • wszelkie ulepszenia tego kodu są mile widziane.

To rozwiązanie wykorzystuje dwie różne metody uzyskania efektu końcowego. Pierwszym jest nadpisanie metod klasy UIFont + systemFontWithSize:i podobnych metodami używającymi moich alternatyw (tutaj używam "Zapfino", aby nie mieć wątpliwości, że zamiana się powiodła).

Inną metodą jest zastąpienie - initWithCoder:metody w UIFont w celu zastąpienia dowolnego wystąpienia CTFontRegularUsagei podobnych przez moje alternatywy. Ta ostatnia metoda była konieczna, ponieważ odkryłem, że UILabelobiekty zakodowane w plikach NIB nie sprawdzają + systemFontWithSize:metod, aby uzyskać czcionkę systemową, a zamiast tego kodują je jako UICTFontDescriptorobiekty. Próbowałem to przesłonić, - awakeAfterUsingCoder:ale w jakiś sposób było to wywoływane dla każdego zakodowanego obiektu w mojej planszy i powodowało awarie. Zastępowanie - awakeFromNibnie pozwala mi odczytać NSCoderobiektu.

#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

Jak używasz tej implementacji na iOS6, która nie ma UIFontDescriptor
Utku Yıldırım

Użyłem klucza dekodera „UIFontTraits”, aby sprawdzić, czy dostarczona czcionka jest pogrubiona lub pochylona, ​​i zastąpiłem ją moimi własnymi odmianami. Mam to z tego sedna tutaj gist.github.com/Daij-Djan/5046612 .
Fábio Oliveira

Dzięki za odpowiedź na razie użyłem innego rozwiązania. Sprawdzę, kiedy będę potrzebował ponownie :)
Utku Yıldırım

2
dziękuję @ FábioOliveira, działa jak urok! Jeszcze tylko jedna rzecz, którą musisz umieścić #import <objc / runtime.h> w nagłówku, w przeciwnym razie otrzymasz błąd, używając klasy 'Method' (błąd, który otrzymuję w XCode 6)
nahung89

Z jakiegoś powodu w iOS 8 modals ( UIAlertController) nie zmieniają czcionki.
Randomblue

13

Aby uzupełnić odpowiedź Sandy Chapman , oto rozwiązanie w Objective-C (umieść tę kategorię w dowolnym miejscu, w którym chcesz zmienić UILabel Appearance):

@implementation UILabel (FontOverride)
- (void)setSubstituteFontName:(NSString *)name UI_APPEARANCE_SELECTOR {
    self.font = [UIFont fontWithName:name size:self.font.pointSize];
}
@end

Plik interfejsu powinien mieć tę metodę zadeklarowaną publicznie do późniejszego użycia z miejsc takich jak delegat aplikacji:

@interface UILabel (FontOverride)
  - (void)setSubstituteFontName:(NSString *)name UI_APPEARANCE_SELECTOR;
@end

Następnie możesz zmienić za Appearancepomocą:

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

1
Cześć, czy masz na myśli „gdziekolwiek”, ten kod musiałby być dodany w każdym kontrolerze widoku i mieć każdy UILabel używany w kontrolerze, gdzie chciałbyś zmienić czcionkę?
Jules

Nie, musisz umieścić ten kod raz , w dowolnym miejscu w projekcie; na przykład w Twojej appdelegate .
Damien Debin

1
@DamienDebin Chcę użyć pogrubionej czcionki dla pogrubienia, ale to zmienia pogrubienie na jasne. W jakiś sposób?
Zeeshan,

Właściwie to działa, ale czy powinno to być „Kategoria” czy „Rozszerzenie”? Różnica wyjaśniona tutaj: stackoverflow.com/questions/7136124/ ...
Darius Miliauskas

4

KOMENTARZ DLA SWIFT 3.0 I SWIFT WARNING

Możesz usunąć ostrzeżenie w linii:

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

Zamieniając go na:

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

Lol. Nie wiedziałem, że Swift pozwala na użycie tego. Btw, zaktualizuję to do powyższej odpowiedzi. Dzięki @ucotta!
nahung89

4

Dla Swift 5

Wszystkie powyższe odpowiedzi są poprawne, ale zrobiłem to w trochę inny sposób, w zależności od rozmiaru urządzenia . Tutaj, w klasie ATFontManager, ustawiłem domyślny rozmiar czcionki, który jest zdefiniowany na górze klasy jako defaultFontSize , jest to rozmiar czcionki iphone plus i możesz go zmienić zgodnie z wymaganiami.

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

Dodałem nazwę czcionki, aby uzyskać więcej, możesz dodać nazwę czcionki i wpisać tutaj.

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

Ta klasa odnosi się do detektora urządzeń w celu zapewnienia odpowiedniego rozmiaru czcionki w zależności od urządzenia.

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

Jak używać. Mam nadzieję, że to pomoże.

//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

Żadne z tych rozwiązań nie działa uniwersalnie w całej aplikacji. Jedną z rzeczy, które pomogły mi w zarządzaniu czcionkami w Xcode, jest otwarcie Storyboard jako kodu źródłowego (Control-click storyboard w nawigatorze plików> „Open as”> „Source”), a następnie wykonanie funkcji „znajdź i zamień”.


3

Typ czcionki zawsze należy ustawić w kodzie i końcówce / scenorysie.

Ponieważ kod, tak jak powiedział Hugues BR , zrób to w kategorii może rozwiązać problem.

W przypadku końcówki / storyboardu możemy metodą Swizzling awakeFromNib zmienić typ czcionki, ponieważ element interfejsu użytkownika z końcówki / serii ujęć zawsze wywołuje ją przed wyświetleniem na ekranie.

Przypuszczam, że znasz Aspects . To biblioteka do programowania AOP, oparta na Method Swizzling. Tworzymy kategorię dla UILabel, UIButton, UITextView, aby ją zaimplementować.

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

To wszystko, możesz zmienić HelveticaNeue-light na makro z nazwą swojej czcionki.


3

Stworzyłem własną konwersję typografii dla Swift 4 po przejrzeniu kilku postów, obejmuje ona większość przypadków, takich jak:

1. Dodaj czcionki do struktury projektu i do pliku .plist (o tej samej nazwie):

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

Następnie

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

Na koniec wywołaj utworzoną metodę Appdelegatejak dalej:

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

        UIFont.overrideDefaultTypography()
        return true
    }
}

@sheshnath czy możesz podać nam więcej informacji o awariach?
Javier Amor Penas

1
przepraszam, pomyłka była z mojej strony, czcionka nie została wymieniona na info.plist
shesh nath

@midhunp Czy mógłbyś wyrazić się bardziej jednoznacznie, aby to nie działało dla Ciebie ?. U mnie działa dobrze z pogrubioną czcionką.
Javier Amor Penas

2

Prawdopodobnie nie, prawdopodobnie sam ustawisz czcionkę na swojej kontrolce, ale możesz ułatwić ten proces, scentralizując miejsce, z którego pobierasz typy czcionek, na przykład delegat aplikacji lub inna wspólna klasa ma metodę, która zwraca czcionka i wszystko, co potrzebne do ustawienia czcionki, może wywołać tę metodę, co pomoże w przypadku konieczności zmiany czcionki, należy ją zmienić w jednym miejscu, a nie wszędzie tam, gdzie ustawisz czcionki ... Inną alternatywą może być utworzenie podklas elementy interfejsu użytkownika, które automatycznie ustawią czcionkę, ale może to być przesada.


dla przypomnienia, to właśnie zrobiłem, ale @Randall potrzebował przedstawiciela i udzielił dobrej odpowiedzi. Po prostu muszę obsługiwać mniej niż 5,0
Sam Jarman,

4
Nie zgadzam się z tym, co zrobiłeś. Wybrana odpowiedź jest nieprawidłowa, gdy Twoje pytanie jest oznaczone tagiem iphone-sdk-4.0.
Paulo Casaretto

@Sam Jarman, odpowiedź Randalla poniżej jest prawidłowa - czy możesz to oznaczyć w ten sposób dla przyszłych gości?
Bill

1

NUI jest alternatywą dla proxy UIAppearance. Zapewnia kontrolę nad czcionką (i wieloma innymi atrybutami) dużej liczby typów elementów interfejsu użytkownika w całej aplikacji, po prostu modyfikując arkusz stylów, który można ponownie wykorzystać w wielu aplikacjach.

Po dodaniu NUILabelklasy do etykiet możesz łatwo kontrolować ich czcionkę w arkuszu stylów:

LabelFontName    String    Helvetica

Jeśli masz etykiety z różnymi rozmiarami czcionek, możesz kontrolować ich rozmiary za pomocą klas NUI Label, LargeLabel i SmallLabel, a nawet szybko utworzyć własne klasy.


1

Szybko używam tego typu klasy czcionek. Korzystanie z klasy rozszerzenia czcionki.

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

Dla Xamarin.iOS wewnątrz AppDelegate FinishedLaunching()umieścić kod w następujący sposób: -

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

ustaw czcionkę dla całej aplikacji i dodaj UIAppFontsklawisz ' ' na Info.plist, ścieżka powinna być ścieżką, w której znajduje się plik czcionki .ttf, dla mnie był to folder 'fonts' w moim projekcie.

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

0

Jak wspomniał @Randall, UIApperanceproxy iOS 5.0+ można wykorzystać do dostosowania wyglądu wszystkich instancji klasy, czytaj więcej .

Automatyczne uzupełnianie Xcodes nie pokazuje wszystkich dostępnych właściwości i może spowodować błąd, ale możesz go po prostu wpisać i skompilować.

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

-1

Osiągnęliśmy to samo w Swift -Xcode 7.2 przy użyciu kontrolera widoku rodzica i kontrolera widoku dziecka (dziedziczenie).

Plik - Nowy - Klasa 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)
        }
    }    

Utwórz kontrolery widoku podrzędnego i skojarz je z StoryBoard VC, dodaj textLabel.

    import UIKit

    class FontTestController: ParentViewController {
        @IBOutlet var testLabel: UILabel!

        override func viewDidLoad() {
            super.viewDidLoad()
            testLabel.font =  appFont
            testLabel.textColor = appUIColor
        }

LUB Utwórz niestandardową klasę UILabel (metoda podklasy) i skojarz z nią wymagane etykiety.

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

Uwaga: Czcionka i kolor zadeklarowane w nadrzędnym VC są zaimplementowane w CustomFontLabel. Zaletą jest to, że możemy razem zmieniać właściwości uilabel / dowolnego widoku za pomocą kilku prostych zmian w Parent VC.

2) „for” zapętlający się UIView dla widoków podrzędnych. Działa tylko na określonym 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)    
                }               
            }       
        }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.