Taille de police personnalisée dans les Classes de taille XCode6 ne fonctionne pas correctement avec les polices personnalisées

Xcode 6 a une nouvelle fonctionnalité où les polices et les tailles de police dans UILabel, UITextField, et UIButton peuvent être réglées automatiquement en fonction de la classe de taille de la configuration actuelle de l'appareil, à droite dans le storyboard. Par exemple, vous pouvez définir un UILabel pour utiliser la taille de police 12 sur "n'importe quelle largeur, hauteur compacte" (comme sur les iPhones dans le paysage) configurations et la taille 18 sur "Largeur régulière, hauteur régulière" configurations (comme sur les iPads). Plus d'informations sont disponibles ici:

https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/Size-ClassSpecificLayout.html

c'est une très bonne caractéristique en théorie parce qu'elle pourrait rendre inutile de programmer différentes polices sur les caractéristiques de L'interface utilisateur en fonction de la configuration de l'appareil. Maintenant, j'ai quelques conditionnelle code qui définit les polices en fonction du type d'appareil, mais, évidemment, cela signifie que je dois mettre les polices par programmation partout dans l'application. Au départ, j'étais très excité par cette fonctionnalité, mais j'ai découvert qu'elle avait un sérieux problème d'utilisation pour moi (peut-être un bug). Notez que je m'appuie sur le SDK 8 et que je fixe un objectif de déploiement minimum de iOS 8, donc cela n'a rien à voir avec la compatibilité avec les anciennes versions de iOS.

le problème est ce: Si je mets différentes tailles de police pour différentes classes de taille et que j'utilise la police "système" fournie par iOS, tout fonctionne comme suit: attendus et les tailles de police varient selon la taille de la classe. Si j'utilise une police personnalisée fournie par mon application (oui, je l'ai correctement configurée dans mon paquet d'application, car elle fonctionne de manière programmatique) et que je place la police personnalisée sur une étiquette dans un storyboard XCode 6, cela fonctionne aussi comme prévu. Mais quand j'essaie d'utiliser des tailles différentes de la police personnalisée pour différentes classes de taille, dans le storyboard, ça ne marche pas du tout. La seule différence dans la configuration est la police que j'ai choisie (une sur mesure vs. le Système de la police). Au lieu de cela, toutes les polices apparaissent sur le périphérique et le simulateur comme la police système par défaut à la taille par défaut, quelle que soit la classe de taille (et j'ai vérifié par l'intermédiaire du débogueur qu'il remplace la police système actuelle spécifiée dans le storyboard). Donc, en gros, la fonctionnalité de classe de taille semble être cassée pour les polices personnalisées. De plus, il est intéressant de noter que les polices personnalisées affichent et ajustent correctement la taille dans le volet "Preview" de XCode 6 pour le contrôleur de vue: lorsque le système iOS tourne, il cesse de fonctionner (ce qui me fait penser que je le configure correctement).

j'ai essayé plusieurs polices différentes et cela ne semble pas fonctionner pour aucune d'entre elles, mais cela fonctionne toujours si j'utilise" Système " à la place.

est-ce que quelqu'un d'autre a vu ce problème dans Xcode 6? Une idée pour savoir si c'est un bug dans iOS 8, Xcode, ou quelque chose que je fais de travers? La seule solution que j'ai trouvée, comme je l'ai dit, est de continuez à programmer les polices comme je l'ai été pour environ 3 versions de iOS, parce que cela fonctionne. Mais j'aimerais pouvoir utiliser cette fonctionnalité si je pouvais la faire fonctionner avec des polices personnalisées. L'utilisation de la police système n'est pas acceptable pour notre conception.


INFORMATIONS SUPPLÉMENTAIRES: À partir de Xcode 8.0, le bug est corrigé.

101
demandé sur Cœur 2014-10-02 22:01:53

14 réponses

Rapide corrigé:

1 )Définir les polices comme système pour les classes de taille

Label attributes inspector

2) sous-classe UILabel et remplacer "layoutSubviews" méthode du type:

- (void)layoutSubviews
{
  [super layoutSubviews];

   // Implement font logic depending on screen size
    if ([self.font.fontName rangeOfString:@"bold" options:NSCaseInsensitiveSearch].location == NSNotFound) {
        NSLog(@"font is not bold");
        self.font = [UIFont fontWithName:@"Custom regular Font" size:self.font.pointSize];
    } else {
        NSLog(@"font is bold");
        self.font = [UIFont fontWithName:@"Custom bold Font" size:self.font.pointSize];
    }

}

soit dit en passant, c'est une technique très commode pour les polices iconiques

40
répondu razor28 2015-11-16 13:36:19

après avoir tout essayé, je me suis finalement fixé sur une combinaison des solutions ci-dessus. En Utilisant Le Xcode 7.2, Swift 2.

import UIKit

class LabelDeviceClass : UILabel {

    @IBInspectable var iPhoneSize:CGFloat = 0 {
        didSet {
            if isPhone() {
                overrideFontSize(iPhoneSize)
            }
        }
    }

    @IBInspectable var iPadSize:CGFloat = 0 {
        didSet {
            if isPad() {
                overrideFontSize(iPadSize)
            }
        }
    }

    func isPhone() -> Bool {
        // return UIDevice.currentDevice().userInterfaceIdiom == .Phone
        return !isPad()
    }

    func isPad() -> Bool {
        // return UIDevice.currentDevice().userInterfaceIdiom == .Pad
        switch (UIScreen.mainScreen().traitCollection.horizontalSizeClass, UIScreen.mainScreen().traitCollection.verticalSizeClass) {
        case (.Regular, .Regular):
            return true
        default:
            return false
        }
    }

    func overrideFontSize(fontSize:CGFloat){
        let currentFontName = self.font.fontName
        if let calculatedFont = UIFont(name: currentFontName, size: fontSize) {
            self.font = calculatedFont
        }
    }

}
  • @IBInspectable vous permet de définir la taille de la police dans le Storyboard
  • il utilise un observateur didSet , pour éviter les pièges de layoutSubviews() (boucle infinie pour les hauteurs dynamiques de la table) et awakeFromNib() (voir le commentaire de @cocoaNoob)
  • il utilise des classes de taille plutôt que l'idiome de l'appareil, dans l'espoir d'utiliser éventuellement ce avec @IBDesignable
  • Malheureusement, @IBDesignable ne fonctionne pas avec traitCollection , selon cet autre "1519200920 pile" article
  • la déclaration de l'interrupteur de collecte de trait est effectuée sur UIScreen.mainScreen() plutôt que self par ce article de pile
17
répondu Robert Chen 2017-05-23 12:00:25

solution de contournement pour UILabel : conserver la même taille de police sur toutes les classes de taille, mais changer la hauteur de votre étiquette en conséquence dans chaque classe de taille. Votre étiquette doit avoir autoshrink activé. Il a travaillé très bien l'affaire dans mon cas.

9
répondu Phil 2015-05-06 16:22:23

ce bug (et d'autres Classes de taille de Xcode) m'a causé de sérieux ennuis récemment car j'ai dû passer par un énorme hacking de fichier storyboard.

pour toute autre personne dans cette position, j'aimerais ajouter quelque chose en plus de la réponse de @razor28 pour soulager la douleur.

dans le fichier d'en-tête de votre sous-classe personnalisée, utilisez IBInspectable pour vos attributs d'exécution. Cela rendra ces attributs accessibles à partir de "L'Inspecteur des attributs"", visuellement juste au-dessus de la position par défaut pour les paramètres de police.

exemple d'utilisation:

@interface MyCustomLabel : UILabel

    @property (nonatomic) IBInspectable NSString *fontType;
    @property (nonatomic) IBInspectable CGFloat iphoneFontSize;
    @property (nonatomic) IBInspectable CGFloat ipadFontSize;

@end

cela va très utilement produire cette sortie:

enter image description here

un avantage supplémentaire est que maintenant nous n'avons pas à ajouter les attributs runtime manuellement pour chaque étiquette. C'est le plus proche que J'ai pu obtenir du comportement prévu de XCode. Avec un peu de chance, iOS 9 est en route cet été.

8
répondu joakim 2015-06-03 18:22:56

solution similaire à celle de @razor28 mais je pense un peu plus universelle. Aussi, fonctionne très bien sur les versions iOS plus anciennes

https://gist.github.com/softmaxsg/8a3ce30331f9f07f023e

3
répondu Vitaly 2015-04-02 20:00:26

le bogue est toujours valide dans XCode 7.0 GM.

la solution de Razor28 provoque des boucles infinies dans certains cas. Mon expérience a été de l'utiliser en conjonction avec SwipeView .

à la place, je vous suggère:

1) sous-classe UILabel et remplacer setFont:

- (void)setFont:(UIFont *)font
{
    font = [UIFont fontWithName:(@"Montserrat") size:font.pointSize];
    [super setFont:font];
}

2) définir la classe personnalisée de vos UILabels et ensuite définissez les classes de taille de police en utilisant la police système

enter image description here

2
répondu Foti Dim 2015-09-11 09:30:34

le problème est toujours là que vous ne pouvez pas utiliser la fonctionnalité pour définir des polices pour différentes classes de taille de interface builder.

Juste définir la police en fonction de l'appareil que vous voulez comme ci-dessous:

if (Your Device is iPAd) //For iPad
{
   [yourLabel setFont:[UIFont fontWithName:@"FontName" size:FontSize]]; 
}
else  //For Other Devices then iPad
{
   [yourLabel setFont:[UIFont fontWithName:@"FontName" size:FontSize]]; 
}

Cela fonctionne parfaitement sur tous les appareils.

0
répondu Nirmit Dagly 2015-10-28 06:54:53

aucun de ceux-ci n'a fonctionné pour moi, mais cela a fonctionné. Vous devez également utiliser la police système dans IB

#import <UIKit/UIKit.h>

@interface UILabelEx : UILabel


@end

#import "UILabelEx.h"
#import "Constants.h"

@implementation UILabelEx

- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {
    [super traitCollectionDidChange: previousTraitCollection];

    self.font = [UIFont fontWithName:APP_FONT size:self.font.pointSize];   
}
@end
0
répondu Jules 2015-11-13 09:15:25

toujours pas de réponse droite signée. Ce code fonctionne très bien pour moi. Vous devez désactiver la taille de police pour les classes de taille dans interface builder en premier. En IB, vous pouvez utiliser une police personnalisée.

- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection {
    [super traitCollectionDidChange: previousTraitCollection];

    if ((self.traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass)
        || self.traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass) {

         self.textField.font = [UIFont fontWithName:textField.font.fontName size:17.f];

    }
}
0
répondu Max Smirnov 2016-06-19 10:21:46

une combinaison de quelques-unes des réponses ultérieures ci-dessus ont été utiles. Voici comment j'ai résolu Le bogue IB via une extension UILabel Swift:

import UIKit

// This extension is only required as a work-around to an interface builder bug in XCode 7.3.1
// When custom fonts are set per size class, they are reset to a small system font
// In order for this extension to work, you must set the fonts in IB to System
// We are switching any instances of ".SFUIDisplay-Bold" to "MuseoSans-700" and ".SFUIDisplay-Regular" to "MuseoSans-300" and keeping the same point size as specified in IB

extension UILabel {
    override public func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)

        if ((traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass) || traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass) {
            //let oldFontName = "\(font.fontName)-\(font.pointSize)"

            if (font.fontName == systemFontRegular) {
                font = UIFont(name: customFontRegular, size: (font?.pointSize)!)
                //xlog.debug("Old font: \(oldFontName) -> new Font: \(font.fontName) - \(font.pointSize)")
            }
            else if (font.fontName == systemFontBold) {
                font = UIFont(name: customFontBold, size: (font?.pointSize)!)
                //xlog.debug("Old font: \(oldFontName) -> new Font: \(font.fontName) - \(font.pointSize)")
            }
        }
    }
}
0
répondu benjam 2016-07-07 00:27:00

J'utilise Swift, XCode 6.4. C'est donc ce que j'ai fait

import Foundation
import UIKit

    @IBDesignable class ExUILabel: UILabel {

        @IBInspectable var fontName: String = "Default-Font" {
            didSet {
                self.font = UIFont(name: fontName, size:self.font.pointSize)
            }
        }

        override func layoutSubviews() {
            super.layoutSubviews()
            self.font = UIFont(name: fontName, size:self.font.pointSize)
        }
    }
  1. Goto Designer -> Identity Inspector -> Set the class to Aguilabel

  2. ensuite, allez à attribut inspector dans designer et définissez le nom de la police.

-1
répondu kakopappa 2015-09-21 16:37:04

j'ai trouvé un correctif encore plus rapide (je suppose que vous utilisez toujours votre police personnalisée).

créer une catégorie pour UILabel et inclure dans les fichiers en utilisant buggy storyboard avec des classes de taille et le réglage de police dédiée pour diverses classes:

@implementation UILabel (FontFixForSizeClassesAppleBug)

- (void)layoutSubviews
{
    [super layoutSubviews];
    if([[UIFont systemFontOfSize:10].familyName isEqualToString:self.font.familyName]) {
        //workaround for interface builder size classes bug which ignores custom font if various classes defined for label: /q/custom-font-sizing-in-xcode6-size-classes-not-working-properly-with-custom-fonts-58562/"YOUR_CUSTOM_FONT_NAME" size:self.font.pointSize];
    }
}

@end

utilisez simplement vos polices de caractères personnalisées dans storyboard. Lorsque buggy interpreter utilisera la police système à la place de la vôtre, cette catégorie l'activera sur votre police personnalisée.

-1
répondu Heps 2016-05-10 10:19:31

j'ai eu le même problème et j'en ai trouvé un pas vraiment clair, mais bonne solution!

  1. d'abord, vous définissez la taille de police requise dans le storyboard avec le nom de police du système.
  2. puis à cette étiquette vous assignez une étiquette de 100 à 110 (ou plus, mais 10 était toujours suffisant pour moi dans un contrôleur de vue).
  3. alors mettez ce code dans le fichier source de votre CV et n'oubliez pas de changer le nom de la police. Code swift.
override func viewDidLayoutSubviews() {
    for i in 100...110 {
        if let label = view.viewWithTag(i) as? UILabel {
            label.font = UIFont(name: "RotondaC-Bold", size: label.font.pointSize)
        }
    }
}
-6
répondu serg_ov 2015-06-15 13:44:26
  • ajouter les polices fournies par application dans votre application.plist
  • ajouter votre .ttf fichier de l'élément 0
  • l'utiliser [UIFont fontWithName:" exemple.ttf" taille:10]
-8
répondu user2612184 2015-01-19 07:06:17