Définir une police par défaut pour toute l'application iOS?

155

J'ai une police personnalisée que je souhaite utiliser pour tout ce qui affiche du texte dans mon application, des étiquettes, des vues de texte, etc.

Existe-t-il un moyen de définir la police par défaut (les étiquettes par défaut utilisent SystemFont) pour l'ensemble de l'application?

Sam Jarman
la source
7
Ayant massivement regardé ce malheur. Nous avons honnêtement trouvé que la chose la plus simple à faire est de créer une nouvelle classe (triviale), pour chaque contrôle. Donc, pour UIButton, créez SJButton. N'oubliez pas de remplacer à la fois initWithFrame et initWithCode. Pour chaque contrôle (disons UIButton, etc.) définissez les couleurs ou ce que vous voulez. Prenez soigneusement, par exemple, la taille (c'est-à-dire que ce sera la taille FIXÉE SUR LE STORYBOARD) dans le code int, puis (comme vous préférez) utilisez cette taille (et définissez, par exemple, la police, la couleur - peu importe). Il ne s'agit que de quelques lignes de code, est incroyablement bien rangé et vous fait gagner beaucoup de temps à long terme.
Fattie
@JoeBlow Merci d'avoir publié vos résultats - j'étais sur le point de passer du temps à chercher à y répondre moi
jj.
@ jj- C'est vrai. N'oubliez pas que vous devez certainement utiliser IBDesignableces jours-ci. J'espère que ça aide. Considérez également ce QA intéressant: stackoverflow.com/a/38000466/294884
Fattie

Réponses:

158

Cela semble possible dans iOS 5 en utilisant le proxy UIAppearance.

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

Cela définira la police quelle que soit votre police personnalisée pour tous les UILabels de votre application. Vous devrez le répéter pour chaque contrôle (UIButton, UILabel, etc.).

N'oubliez pas que vous devrez mettre la valeur UIAppFonts dans votre info.plist et inclure le nom de la police que vous incluez.

Randall
la source
46
Merci pour la réponse. J'ai pu faire fonctionner cela. Savez-vous s'il existe un moyen de spécifier la police sans spécifier la taille de la police? J'ai des étiquettes dans mon application qui ne partagent pas la même taille de police.
Brandon le
23
Puis-je faire cela sans remplacer la taille en points de chaque instance?
Michael Forrest
17
setFont:méthode est obsolète
Anand
12
@Anet en êtes-vous sûr? Je ne le vois pas marqué comme obsolète dans UILabel. Il est déconseillé pour, UIButtonmais il utilise la police de la titleLabelpropriété à la place qui est a UILabel, donc il suffit de définir la police avec le proxy d'apparence pour UILabel.
Adrian Schönig
6
@Anand il n'est pas obsolète pour UILabel.
Alastair Stuart
118

Swift 5

Sur la base de la réponse de Fábio Oliveira ( https://stackoverflow.com/a/23042694/2082851 ), je crée mon propre swift 4.

En bref, cette échange d'extension des fonctions par défaut init(coder:), systemFont(ofSize:), boldSystemFont(ofSize:), italicSystemFont(ofSize:)avec mes méthodes personnalisées.

Notez que ce n'est pas entièrement implémenté, mais vous pouvez échanger plus de méthodes basées sur mon implémentation.

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()
    }
    ...
}
nahung89
la source
2
meilleure réponse!! remplacer automatiquement la police système, brillant
Kappe
2
Si quelqu'un a des problèmes avec la ligne "NSCTFontUIUsageAttribute": if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String {fait l'affaire pour moi.
Connaissance du
1
ne semble pas fonctionner avec les UILabels qui définissent le style de texte (gras, titre, titre, etc.) ... ne fonctionne qu'avec des polices qui ont une taille et un jeu de polices système spécifiques. @ nahung89
aviran
1
Cela change également certaines polices de l'interface utilisateur du système. Par exemple, la liste de suggestions de clavier et la feuille d'action. Je ne sais pas si cela poussera Apple à rejeter l'application
Henry H Miao
1
Cela fait un an que cette réponse a été publiée. Quelqu'un a-t-il un moyen Apple plus "natif" pour y parvenir?
Greg Hilston
75

Il existe également une autre solution qui sera de surcharger systemFont.

Créez simplement une catégorie

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

Cela remplacera l'implémentation par défaut et la plupart des UIControls utilisent systemFont.

Hugues BR
la source
1
Est-ce conforme aux directives Apple?
Rambatino
C'est plus un hack. Je n'ai pas ajouté mon registre d'application avec ce hack, car il n'utilise aucune méthode privée. Si vous voulez une solution plus robuste, je vous suggère également de vérifier ceci: github.com/0xced/FontReplacer
Hugues BR
2
C'est bon. Apple ne veut tout simplement pas que vous utilisiez des fonctions non documentées. Vous êtes autorisé à «swizzler» les méthodes qui sont publiques.
mxcl
4
Lorsqu'une catégorie a des méthodes avec la même signature que la classe qu'elle étend, le comportement n'est pas défini. Pour remplacer les méthodes de classe, vous devez utiliser la méthode swizzling (ce qui n'est pas non plus une bonne idée).
GreatWiz
1
Comme d'autres l'ont souligné, cette solution, bien que susceptible d'être efficace la plupart du temps, introduit techniquement le potentiel d'un comportement indéfini. Si vous n'avez pas envie de le risquer, la méthode swizzling pourrait être une meilleure option. La réponse ici fournit la même solution via swizzling: stackoverflow.com/questions/19542942/…
Nathan Hosselton
64

Si vous utilisez Swift, vous pouvez créer une extension UILabel:

extension UILabel {

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

}

Et puis où vous faites votre proxy d'apparence:

UILabel.appearance().substituteFontName = applicationFont

Un code Objective-C équivalent est utilisé UI_APPEARANCE_SELECTORsur une propriété avec le nom substituteFontName.

Une addition

Dans le cas où vous souhaitez définir séparément les polices gras et normaux:

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

Ensuite, pour vos proxys UIAppearance:

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

Remarque: si vous constatez que la substitution en gras ne fonctionne pas, il est possible que le nom de la police par défaut ne contienne pas "Medium". Changez cette chaîne pour une autre correspondance si nécessaire (merci à Mason dans les commentaires ci-dessous).

Sandy Chapman
la source
Un inconvénient à cela que j'ai trouvé est que lorsque j'initie des alertes avec UIAlertController, le bouton avec le style .Cancel est le même que le bouton avec le style .Default (au moins lorsque vous utilisez GillSans). Alors que normalement .Cancel serait une police de poids normal, et .Default serait en gras. Des idées?
Mason G. Zhwiti
Désolé, je voulais dire que les libellés .Annuler seraient normalement en gras et la valeur par défaut serait normalement de poids normal.
Mason G. Zhwiti
2
@ MasonG.Zhwiti Dans ce cas, je configurerais probablement l' UILabelextension pour prendre un nom de police supplémentaire pour gras. Ensuite, setfaites une vérification pour voir si "Gras" est dans le nom de la police et ignorez le jeu dans un cas et utilisez-le dans l'autre. Je vais éditer et ajouter un exemple.
Sandy Chapman
@SandyChapman Merci! J'essaie cette nouvelle technique, et cela a du sens, mais cela ne semble pas fonctionner pour moi. J'utilise GillSans et GillSans-Bold sur le simulateur iOS 8.3. Avez-vous testé cette technique?
Mason G. Zhwiti
2
@SandyChapman J'ai compris ce qui se passe. Les polices par défaut pour iOS 8 ont tendance à être HelveticaNeueInterface-Regular ou (en gras) HelveticaNeueInterface-MediumP4. Donc, chercher "Bold" ne correspondait jamais à rien. Je l'ai changé rangeOfString("Medium")et cela a fonctionné.
Mason G. Zhwiti
23

En développant à partir de la réponse de Hugues BR mais en utilisant la méthode swizzling, je suis arrivé à une solution qui transforme avec succès toutes les polices en une police souhaitée dans mon application.

Une approche avec Dynamic Type devrait être ce que vous devriez rechercher sur iOS 7. La solution suivante n'utilise pas Dynamic Type.


Remarques:

  • le code ci-dessous, dans son état présenté, n'a jamais été soumis à l'approbation d'Apple;
  • il existe une version plus courte de celui-ci qui a réussi la soumission d'Apple, c'est-à-dire sans le - initWithCoder:remplacement. Cependant, cela ne couvrira pas tous les cas;
  • le code suivant est présent dans une classe que j'utilise pour définir le style de mon application qui est inclus par ma classe AppDelegate étant ainsi disponible partout et à toutes les instances UIFont;
  • J'utilise Zapfino ici juste pour rendre les changements beaucoup plus visibles;
  • toute amélioration que vous pourriez trouver à ce code est la bienvenue.

Cette solution utilise deux méthodes différentes pour obtenir le résultat final. Le premier est de remplacer les méthodes de classe UIFont + systemFontWithSize:et similaires par celles qui utilisent mes alternatives (ici, j'utilise "Zapfino" pour ne laisser aucun doute sur le succès du remplacement).

L'autre méthode consiste à remplacer la - initWithCoder:méthode sur UIFont pour remplacer toute occurrence de CTFontRegularUsageet similaire par mes alternatives. Cette dernière méthode était nécessaire car j'ai constaté que les UILabelobjets encodés dans des fichiers NIB ne vérifient pas les + systemFontWithSize:méthodes pour obtenir leur police système et les encodent en tant UICTFontDescriptorqu'objets. J'ai essayé de remplacer - awakeAfterUsingCoder:mais d'une manière ou d'une autre, il était appelé pour chaque objet codé dans mon storyboard et provoquait des plantages. Le remplacement - awakeFromNibne me permettrait pas de lire l' NSCoderobjet.

#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
Fábio Oliveira
la source
Comment vous utilisez cette implémentation sur iOS6 qui n'a pas UIFontDescriptor
Utku Yıldırım
J'ai utilisé la clé de décodeur "UIFontTraits" pour vérifier si la police fournie est en gras ou en italique et la remplacer par mes propres variations. Je l'ai obtenu à partir de l'essentiel ici gist.github.com/Daij-Djan/5046612 .
Fábio Oliveira
Merci pour la réponse, j'ai utilisé une autre solution pour le moment. Je le vérifierai quand
j'en aurai à
2
merci @ FábioOliveira, ça marche comme un charme! Encore une chose dont vous avez besoin pour mettre #import <objc / runtime.h> sur l'en-tête, sinon vous obtiendrez une erreur en utilisant la classe 'Method' (erreur que j'obtiens dans XCode 6)
nahung89
Pour une raison quelconque, sur iOS 8, les modaux ( UIAlertController) ne changent pas de police.
Randomblue
13

Pour compléter la réponse de Sandy Chapman , voici une solution en Objective-C (mettez cette catégorie partout où vous voulez changer UILabel Appearance):

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

Le fichier d'interface doit avoir cette méthode déclarée publiquement pour être utilisée ultérieurement à partir d'endroits tels que votre délégué d'application:

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

Ensuite, vous pouvez changer le Appearanceavec:

[[UILabel appearance] setSubstituteFontName:@"SourceSansPro-Light"];
Damien Debin
la source
1
Salut, voulez-vous dire "n'importe où", ce code devrait être ajouté dans chaque contrôleur de vue, et chaque UILabel utilisé dans le contrôleur, où vous souhaitez changer la police?
Jules
Non, vous devez mettre ce code une fois , n'importe où dans votre projet; dans votre appdelegate par exemple.
Damien Debin
1
@DamienDebin Je veux utiliser une police en gras pour le gras, mais cela change de gras en clair. Un moyen de contourner?
Zeeshan
En fait, ça marche, mais devrait-il être "Catégorie" ou "Extension"? La différence expliquée ici: stackoverflow.com/questions/7136124/…
Darius Miliauskas
4

COMMENTAIRE POUR SWIFT 3.0 ET AVERTISSEMENT SWIFT

Vous pouvez supprimer le message d'avertissement en ligne:

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

En le remplaçant par:

let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:)))
ucotta
la source
Lol. Je ne savais pas que Swift permettait d'utiliser cela. Btw, je vais le mettre à jour à la réponse ci-dessus. Merci @ucotta!
nahung89
4

Pour Swift 5

Toutes les réponses ci-dessus sont correctes, mais je l'ai fait d'une manière peu différente en fonction de la taille de l'appareil . Ici, dans la classe ATFontManager, j'ai défini la taille de police par défaut qui est définie en haut de la classe comme defaultFontSize , c'est la taille de police de l' iphone plus et vous pouvez la modifier en fonction de vos besoins.

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

J'ai ajouté un certain nom de police, pour plus, vous pouvez ajouter le nom et le type de police ici.

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

Cette classe fait référence au détecteur de périphérique afin de fournir une taille de police appropriée en fonction du périphérique.

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

Comment utiliser. J'espère que cela aidera.

//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)
Amrit Tiwari
la source
3

Aucune de ces solutions ne fonctionne universellement dans toute l'application. Une chose que j'ai trouvée pour aider à gérer les polices dans Xcode est d'ouvrir le Storyboard en tant que code source (Control-click storyboard dans le navigateur de fichiers> "Ouvrir en tant que"> "Source"), puis de faire une recherche et un remplacement.

Gingi
la source
3

Le type de police doit toujours être défini dans le code et la pointe / le storyboard.

Pour le code, tout comme Hugues BR l'a dit , le faire en catégorie peut résoudre le problème.

Pour la nib / storyboard, nous pouvons utiliser la méthode Swizzling awakeFromNib pour changer le type de police puisque l'élément d'interface utilisateur de nib / storyboard l'appelle toujours avant de s'afficher à l'écran.

Je suppose que vous connaissez Aspects . C'est une bibliothèque pour la programmation AOP, basée sur Method Swizzling. Nous créons une catégorie pour UILabel, UIButton, UITextView pour l'implémenter.

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

C'est tout, vous pouvez changer HelveticaNeue-light en macro avec votre nom de police.

Peng Xiaofeng
la source
3

J'ai créé ma propre conversion de typographie pour Swift 4 après avoir examiné quelques articles, elle couvre la plupart des cas, tels que:

1er Ajouter des polices à la structure du projet et au fichier .plist (avec le même nom):

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

ensuite

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

Enfin, appelez la méthode créée à la Appdelegatesuivante:

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

        UIFont.overrideDefaultTypography()
        return true
    }
}
Javier Amor Penas
la source
@sheshnath pouvez-vous nous donner plus d'informations sur les crashs?
Javier Amor Penas
1
désolé erreur était de mon côté, la police n'était pas répertoriée dans info.plist
shesh nath
@midhunp Pourriez-vous être plus explicite pour que cela ne fonctionne pas pour vous ?. Cela fonctionne bien pour moi avec une police de caractères audacieuse.
Javier Amor Penas
2

Probablement pas, vous aurez probablement défini la police sur votre contrôle vous-même, mais vous pouvez faciliter le processus en centralisant d'où vous obtenez les types de polices, par exemple, demandez au délégué d'application ou à une autre classe commune d'avoir une méthode qui renvoie le font, et tout ce qui a besoin de définir la police peut appeler cette méthode, cela vous aidera au cas où vous auriez besoin de changer votre police, vous la changeriez à un endroit plutôt que partout où vous définissez les polices ... Une autre alternative peut être de créer des sous-classes de vos éléments d'interface utilisateur qui définiront automatiquement la police, mais cela pourrait être excessif.

Daniel
la source
pour mémoire, c'est ce que j'ai fait, mais @Randall avait besoin du représentant et a fourni une bonne réponse. J'ai juste besoin de supporter moins de 5,0
Sam Jarman
4
Je ne suis pas d'accord avec ce que vous avez fait. La réponse que vous avez sélectionnée n'est pas valide lorsque votre question est étiquetée iphone-sdk-4.0.
Paulo Casaretto
@Sam Jarman, la réponse de Randall ci-dessous est correcte - pouvez-vous le marquer de cette façon pour les futurs visiteurs?
Projet de loi du
1

NUI est une alternative au proxy UIAppearance. Il vous permet de contrôler la police (et de nombreux autres attributs) d'un grand nombre de types d'éléments d'interface utilisateur dans toute votre application en modifiant simplement une feuille de style, qui peut être réutilisée dans plusieurs applications.

Après avoir ajouté une NUILabelclasse à vos étiquettes, vous pouvez facilement contrôler leur police dans la feuille de style:

LabelFontName    String    Helvetica

Si vous avez des étiquettes avec différentes tailles de police, vous pouvez contrôler leurs tailles à l'aide des classes Label, LargeLabel et SmallLabel de NUI, ou même créer rapidement vos propres classes.

À M
la source
1

J'utilise comme ce type de classe de police dans Swift. Utilisation de la classe d'extension de police.

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 )!
    }
}
Karthickkck
la source
0

Pour Xamarin.iOS à l'intérieur du FinishedLaunching()code put d'AppDelegate comme ceci: -

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

définir la police pour l'ensemble de l'application et ajouter la UIAppFontstouche ' ' sur Info.plist, le chemin doit être le chemin où se trouve votre fichier de police .ttf .Pour moi, il se trouvait dans le dossier 'polices' de mon projet.

<key>UIAppFonts</key>
    <array>
        <string>fonts/Lato-Regular.ttf</string>
    </array>
Annu
la source
0

Comme @Randall l'a mentionné, le UIApperanceproxy iOS 5.0+ peut être utilisé pour personnaliser l'apparence de toutes les instances d'une classe, en savoir plus .

La saisie semi-automatique Xcodes n'affiche pas toutes les propriétés disponibles et peut générer une erreur, mais vous pouvez simplement le taper et il se compilera.

UILabel.apperance().font = UIFont.systemFont(ofSize: 17, weight: .regular)
esesmuedgars
la source
-1

Nous avons réalisé la même chose dans Swift -Xcode 7.2 en utilisant le contrôleur de vue parent et le contrôleur de vue enfant (héritage).

Fichier - Nouveau - Classe 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)
        }
    }    

Créez des contrôleurs de vue enfants et associez-les à un StoryBoard VC, ajoutez un textLabel.

    import UIKit

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

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

OU Créez une classe UILabel personnalisée (méthode de sous-classification) et associez-y les étiquettes requises.

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

Remarque: La police et la couleur déclarées dans Parent VC sont implémentées dans CustomFontLabel. L'avantage est que nous pouvons modifier les propriétés de uilabel / any view en quelques modifications simples dans Parent VC.

2) 'pour' boucler UIView pour les sous-vues. Cela ne fonctionne que sur un VC particulier.

    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)    
                }               
            }       
        }
AG
la source