Definir uma fonte padrão para todo o aplicativo iOS?

155

Eu tenho uma fonte personalizada que quero usar para tudo que exibe texto no meu aplicativo, rótulos, visualizações de texto etc.

Existe uma maneira de definir a fonte padrão (rótulos, por padrão, use SystemFont) para todo o aplicativo?

Sam Jarman
fonte
7
Tendo examinado maciçamente esse sofrimento. Sinceramente, descobrimos que a coisa mais simples a fazer é criar uma nova classe (trivial) para cada controle. Então, para UIButton, faça SJButton. Não se esqueça de substituir initWithFrame e initWithCode. Para cada controle (digamos UIButton, etc), defina as cores ou o que quiser. Escolha com cuidado, diga o tamanho (ou seja, será o tamanho SET NO STORYBOARD) no código int e, em seguida (como preferir), use esse tamanho (e defina, digamos, a fonte, a cor - qualquer que seja). São apenas algumas linhas de código, são incrivelmente arrumadas e economizam muito tempo a longo prazo.
Fattie
@JoeBlow Obrigado por postar suas descobertas - estava prestes a gastar tempo procurando responder a mim mesmo
jj.
@ jj- Certo. Não se esqueça também, você certamente DEVE usar IBDesignableesses dias. Espero que ajude. Considere também este QA interessante: stackoverflow.com/a/38000466/294884
Fattie

Respostas:

158

Parece possível no iOS 5 usando o proxy UIAppearance.

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

Isso definirá a fonte para qualquer que seja sua fonte personalizada para todos os UILabels do seu aplicativo. Você precisará repeti-lo para cada controle (UIButton, UILabel etc.).

Lembre-se de que você precisará colocar o valor UIAppFonts no seu info.plist e incluir o nome da fonte que você está incluindo.

Randall
fonte
46
Obrigado pela resposta. Consegui fazer isso funcionar. Você sabe se existe uma maneira de especificar a fonte sem especificar o tamanho da fonte? Tenho marcadores no meu aplicativo que não compartilham o mesmo tamanho de fonte.
Brandon
23
Posso fazer isso sem substituir o tamanho do ponto de cada instância?
Michael Forrest
17
setFont:método está obsoleto
Anand
12
@Anand você tem certeza disso? Não o vejo marcado como obsoleto UILabel. Ele foi descontinuado, UIButtonmas, em vez disso, usando a fonte da titleLabelpropriedade que é a UILabel, portanto, basta definir a fonte com o proxy de aparência para UILabel.
Adrian Schönig
6
@ E não é preterido para o UILabel.
Alastair Stuart
118

Swift 5

Com base na resposta de Fábio Oliveira ( https://stackoverflow.com/a/23042694/2082851 ), faço o meu próprio rápido 4.

Em suma, este funções trocas extensão padrão init(coder:), systemFont(ofSize:), boldSystemFont(ofSize:), italicSystemFont(ofSize:)com os meus métodos personalizados.

Observe que não é totalmente implementado, mas você pode trocar mais métodos com base na minha implementação.

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
fonte
2
melhor resposta!! substituir automaticamente a fonte do sistema, brilhante
Kappe
2
Se alguém tiver problemas com a linha "NSCTFontUIUsageAttribute": if let fontAttribute = fontDescriptor.fontAttributes[.nsctFontUIUsage] as? String {fiz o truque para mim.
Conhecimento
1
parece não funcionar com UILabels que definem o estilo de texto (negrito, título, título, etc.) ... funciona apenas com fontes com tamanho específico e fonte do sistema definida. @ nahung89
aviran
1
Isso também alterna algumas fontes da interface do usuário do sistema. Por exemplo, a lista de sugestões de teclado e a folha de ações. Não sei se isso fará com que a Apple para rejeitar o aplicativo
Henry H Miao
1
Faz um ano desde que esta resposta foi publicada. Alguém tem uma maneira Apple mais "nativa" de conseguir isso?
Greg Hilston
75

Há também outra solução que será substituir o systemFont.

Basta criar uma categoria

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

Isso substituirá a implementação padrão e a maioria dos UIControls usa systemFont.

Hugues BR
fonte
1
Isso está dentro das diretrizes da apple?
Rambatino 22/08/2013
É mais um truque. Não adicionei meu registro de aplicativo com esse hack, pois ele não está usando nenhum método privado. Se você deseja uma solução mais robusta, sugiro também que verifique isso: github.com/0xced/FontReplacer
Hugues BR
2
Isto é bom. A Apple simplesmente não quer que você use funções não documentadas. Você tem permissão para "swizzle" métodos públicos.
Mxcl
4
Quando uma categoria tem métodos com a mesma assinatura que a classe, ela está estendendo o comportamento não definido. Para substituir os métodos de classe, você deve usar o método swizzling (que também não é uma boa ideia).
GreatWiz 14/05
1
Como outros já apontaram, essa solução, embora provavelmente seja eficaz na maioria das vezes, está tecnicamente introduzindo o potencial de comportamento indefinido. Se você não quiser arriscar, o método swizzling pode ser uma opção melhor. A resposta aqui fornece a mesma solução via swizzling: stackoverflow.com/questions/19542942/…
Nathan Hosselton
64

Se você estiver usando o Swift, poderá criar uma extensão UILabel:

extension UILabel {

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

}

E então, onde você faz sua aparência como proxy:

UILabel.appearance().substituteFontName = applicationFont

Há código de Objective-C equivalente usando UI_APPEARANCE_SELECTORem uma propriedade com o nome substituteFontName.

Adição

Para o caso em que você deseja definir fontes em negrito e regulares separadamente:

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

Em seguida, para seus proxies UIAppearance:

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

Nota: se você achar que a substituição em negrito não está funcionando, é possível que o nome da fonte padrão não contenha "Médio". Troque essa sequência para outra partida conforme necessário (graças a Mason nos comentários abaixo).

Sandy Chapman
fonte
Uma desvantagem disso é que, quando inicio alertas com o UIAlertController, o botão com o estilo .Cancel é o mesmo que o botão com o estilo .Default (pelo menos ao usar o GillSans). Considerando que normalmente .Cancel seria uma fonte de ponderação regular, e .Default seria negrito. Alguma ideia?
Mason G. Zhwiti
Desculpe, eu quis dizer. Os rótulos de cancelamento normalmente ficam em negrito e o padrão normalmente tem peso normal.
Mason G. Zhwiti
2
@ MasonG.Zhwiti Nesse caso, eu provavelmente configuraria a UILabelextensão para usar um nome de fonte adicional em negrito. Em seguida, setverifique se "Negrito" está no nome da fonte, ignore o conjunto em um caso e use-o no outro. Vou editar e adicionar um exemplo.
Sandy Chapman
@SandyChapman Thanks! Estou tentando esta nova técnica, e faz sentido, mas não parece estar funcionando para mim. Estou usando o GillSans e o GillSans-Bold no simulador iOS 8.3. Você já testou essa técnica?
Mason G. Zhwiti
2
@SandyChapman eu descobri o que está acontecendo. As fontes padrão do iOS 8 tendem a ser HelveticaNeueInterface-Regular ou (em negrito) HelveticaNeueInterface-MediumP4. Então, procurar por "Negrito" nunca combinava com nada. Eu mudei para rangeOfString("Medium")e funcionou.
Mason G. Zhwiti
23

Desenvolvendo a partir da resposta Hugues BR, mas usando o método swizzling, cheguei a uma solução que está alterando com êxito todas as fontes para a fonte desejada no meu aplicativo.

Uma abordagem com Dynamic Type deve ser o que você deve procurar no iOS 7. A solução a seguir não está usando Dynamic Type.


Notas:

  • o código abaixo, em seu estado apresentado, nunca foi submetido à aprovação da Apple;
  • existe uma versão mais curta que passou na submissão da Apple, sem a - initWithCoder:substituição. No entanto, isso não cobre todos os casos;
  • o código a seguir está presente em uma classe que eu uso para definir o estilo do meu aplicativo, que é incluído pela minha classe AppDelegate, estando disponível em qualquer lugar e em todas as instâncias do UIFont;
  • Estou usando o Zapfino aqui apenas para tornar as alterações muito mais visíveis;
  • qualquer melhoria que você possa encontrar neste código é bem-vinda.

Esta solução usa dois métodos diferentes para alcançar o resultado final. O primeiro é substituir os métodos da classe UIFont + systemFontWithSize:e similares aos métodos que usam minhas alternativas (aqui eu uso o "Zapfino" para não deixar dúvidas de que a substituição foi bem-sucedida).

O outro método é substituir o - initWithCoder:método no UIFont para substituir qualquer ocorrência CTFontRegularUsageou similar pelas minhas alternativas. Esse último método foi necessário porque descobri que os UILabelobjetos codificados nos arquivos NIB não verificam os + systemFontWithSize:métodos para obter a fonte do sistema e, em vez disso, os codificam como UICTFontDescriptorobjetos. Eu tentei substituir, - awakeAfterUsingCoder:mas de alguma forma estava sendo chamado para cada objeto codificado no meu storyboard e causando falhas. Substituir - awakeFromNibnão me permitiria ler o NSCoderobjeto.

#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
fonte
Como você usa essa implementação em iOS6 que não tem UIFontDescriptor
Utku Yıldırım
Usei a chave do decodificador "UIFontTraits" para verificar se a fonte fornecida está em negrito ou itálico e substituí-la pelas minhas próprias variações. Entendi a partir desta essência aqui gist.github.com/Daij-Djan/5046612 .
Fábio Oliveira
Obrigado pela resposta eu usei outra solução por enquanto. Vou verificar isso quando eu precisar dele novamente :)
Utku Yıldırım
2
obrigado @ FábioOliveira, funciona como um encanto! Apenas mais uma coisa que você precisa colocar #import <objc / runtime.h> no cabeçalho, caso contrário, você receberá um erro usando a classe 'Method' (erro que eu recebo no XCode 6)
nahung89
Por alguma razão, no iOS 8, os modais ( UIAlertController) não alteram a fonte.
Randomblue
13

Para completar a resposta de Sandy Chapman , aqui está uma solução no Objective-C (coloque essa categoria em qualquer lugar que você queira alterar UILabel Appearance):

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

O arquivo de interface deve ter esse método declarado publicamente para ser usado posteriormente em locais como o representante do seu aplicativo:

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

Em seguida, você pode alterar o Appearancecom:

[[UILabel appearance] setSubstituteFontName:@"SourceSansPro-Light"];
Damien Debin
fonte
1
Oi, você quer dizer "em qualquer lugar", esse código teria que ser adicionado em todos os controladores de exibição e todos os UILabel usados ​​no controlador, onde você desejava alterar a fonte?
Jules
Não, você deve colocar esse código uma vez , em qualquer lugar do seu projeto; no seu appdelegate, por exemplo.
precisa
1
@DamienDebin Eu quero usar fonte em negrito para negrito, mas isso muda em negrito para claro. Alguma maneira de contornar?
Zeeshan
Na verdade, funciona, mas deveria ser "Categoria" ou "Extensão"? A diferença explicada aqui: stackoverflow.com/questions/7136124/…
Darius Miliauskas
4

COMENTÁRIO DO SWIFT 3.0 E AVISO SWIFT

Você pode remover a mensagem de aviso na linha:

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

Substituindo-o por:

let initCoderMethod = class_getInstanceMethod(self, #selector(UIFontDescriptor.init(coder:)))
ucotta
fonte
Ri muito. Eu não sabia que Swift permitia usar isso. Btw, vou atualizá-lo para a resposta acima. Obrigado @ucotta!
precisa saber é o seguinte
4

Para Swift 5

Todas as respostas acima estão corretas, mas eu fiz de uma maneira um pouco diferente, de acordo com o tamanho do dispositivo . Aqui, na classe ATFontManager, criei o tamanho da fonte padrão, que é definido na parte superior da classe como defaultFontSize , este é o tamanho da fonte do iphone plus e você pode alterar de acordo com sua necessidade.

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

Eu adicionei um determinado nome de fonte; para mais, você pode adicionar o nome da fonte e digitar aqui.

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

Esta classe refere-se ao detector de dispositivo para fornecer o tamanho de fonte apropriado de acordo com o dispositivo.

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

Como usar. Espero que ajude.

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

Nenhuma dessas soluções funciona universalmente em todo o aplicativo. Uma coisa que eu descobri para ajudar a gerenciar as fontes no Xcode é abrir o Storyboard como código-fonte (clique no storyboard com Control e clique em Navegador de arquivos> "Abrir como"> "Origem") e, em seguida, localize e substitua.

Gingi
fonte
3

O tipo de fonte sempre deve ser definido no código e nib / storyboard.

Para o código, assim como Hugues BR disse , fazê-lo na categoria pode resolver o problema.

Para o nib / storyboard, podemos usar o Method Swizzling awakeFromNib para alterar o tipo de fonte, já que o elemento da interface do usuário do nib / storyboard sempre o chama antes de ser exibido na tela.

Suponho que você conhece Aspectos . É uma biblioteca para programação de AOP, baseada no Method Swizzling. Criamos uma categoria para UILabel, UIButton, UITextView para implementá-lo.

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

Isso é tudo, você pode alterar o HelveticaNeue-light para uma macro com o nome da fonte.

Peng Xiaofeng
fonte
3

Criei minha própria conversão de tipografia para o Swift 4 depois de revisar algumas postagens, que abrange a maioria dos casos, como:

1º Adicione fontes à estrutura do projeto e ao arquivo .plist (com o mesmo nome):

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

Então

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

Por fim, chame o método criado da Appdelegateseguinte maneira:

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

        UIFont.overrideDefaultTypography()
        return true
    }
}
Javier Amor Penas
fonte
@sheshnath, você pode nos dar mais informações sobre falhas?
Javier Amor Penas
1
erro pena foi do meu lado, fonte não foi listado no info.plist
Nath shesh
@midhunp Você poderia ser mais explícito para que não funcione para você ?. Funciona bem para mim com letras em negrito.
Javier Amor Penas
2

Provavelmente não, você provavelmente definirá a fonte sob seu controle, mas poderá facilitar o processo centralizando de onde obtém os tipos de fonte, por exemplo, faça o delegado do aplicativo ou alguma outra classe comum ter um método que retorne o fonte, e qualquer coisa que precise defini-la pode chamar esse método, que ajudará no caso de você precisar alterar sua fonte, alterá-la em um local e não em qualquer lugar em que definir as fontes ... Outra alternativa pode ser criar subclasses de seus elementos da interface do usuário que definirão automaticamente a fonte, mas que pode ser um exagero.

Daniel
fonte
para constar, foi o que fiz, mas o @Randall precisava do representante e deu uma boa resposta. Eu só preciso apoiar inferior a 5,0
Sam Jarman
4
Eu discordo do que você fez. A resposta que você selecionou não é válida quando sua pergunta é marcada como iphone-sdk-4.0.
Paulo Casaretto
@ Sam Jarman, a resposta de Randall abaixo está correta - você pode marcar dessa maneira para futuros visitantes?
Bill
1

NUI é uma alternativa ao proxy UIAppearance. Ele oferece controle sobre a fonte (e muitos outros atributos) de um grande número de tipos de elementos de interface do usuário em todo o aplicativo, modificando simplesmente uma folha de estilos, que pode ser reutilizada em vários aplicativos.

Depois de adicionar uma NUILabelclasse aos seus rótulos, você pode controlar facilmente a fonte deles na folha de estilos:

LabelFontName    String    Helvetica

Se você tiver rótulos com tamanhos de fonte diferentes, poderá controlar seus tamanhos usando as classes Label, LargeLabel e SmallLabel da NUI ou até mesmo criar rapidamente suas próprias classes.

Tom
fonte
1

Estou usando como este tipo de classe de fonte em rápido. Usando classe de extensão de fonte.

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

Para o Xamarin.iOS dentro do FinishedLaunching()código de aplicação do AppDelegate, desta forma: -

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

defina a fonte para todo o aplicativo e adicione a UIAppFontstecla ' ' no Info.plist, o caminho deve ser o caminho onde o arquivo de fonte .ttf está situado. Para mim, estava dentro da pasta 'fonts' no meu projeto.

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

Como o @Randall mencionou, o UIApperanceproxy iOS 5.0+ pode ser usado para personalizar a aparência de todas as instâncias de uma classe, leia mais .

O Xcodes auto complete não mostra todas as propriedades disponíveis e pode gerar um erro, mas você pode apenas digitá-lo e ele será compilado.

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

Conseguimos o mesmo no Swift -Xcode 7.2 usando o Parent View Controller e o Child view controller (Herança).

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

Crie controladores de exibição filho e associe-se a um StoryBoard VC, adicione um textLabel.

    import UIKit

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

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

OU Crie uma classe UILabel personalizada (método de subclassificação) e associe os rótulos necessários a ela.

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

Nota: A fonte e a cor declaradas no VC pai são implementadas no CustomFontLabel. A vantagem é que podemos alterar todas as propriedades do uilabel / any view em algumas alterações simples no VC pai.

2) 'for' loop UIView para sub-visualizações. Funciona apenas em um VC específico.

    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
fonte