Benutzerdefinierte Schriftgröße in Xcode 6-Größenklassen funktionieren mit benutzerdefinierten Schriftarten nicht ordnungsgemäß

104

Xcode 6 hat eine neue Funktion in den Schriftart und Schriftgrößen in UILabel, UITextFieldund UIButtonautomatisch auf der Grundlage der Größenklasse der aktuellen Gerätekonfiguration direkt im Storyboard festgelegt werden können. Sie können beispielsweise festlegen UILabel, dass die Schriftgröße 12 für Konfigurationen mit "beliebiger Breite und kompakter Höhe" (z. B. bei iPhones im Querformat) und die Größe 18 für Konfigurationen mit "normaler Breite und normaler Höhe" (z. B. auf iPads ) verwendet wird. Weitere Informationen finden Sie hier:

developer.apple.com/size_class

Dies ist theoretisch eine großartige Funktion, da es möglicherweise unnötig wird, programmgesteuert unterschiedliche Schriftarten für UI-Funktionen basierend auf der Gerätekonfiguration festzulegen. Im Moment habe ich einen bedingten Code, der die Schriftarten basierend auf dem Gerätetyp festlegt, aber das bedeutet natürlich, dass ich die Schriftarten überall in der App programmgesteuert festlegen muss. Ich war anfangs sehr aufgeregt über diese Funktion, aber ich stellte fest, dass es ein ernstes Problem der tatsächlichen Nutzung für mich gibt (möglicherweise ein Fehler). Beachten Sie, dass ich gegen SDK 8 baue und ein Mindestbereitstellungsziel für iOS 8 festlege. Dies hat also nichts mit der Kompatibilität mit alten Versionen von iOS zu tun.

Das Problem ist folgendes: Wenn ich unterschiedliche Schriftgrößen für unterschiedliche Größenklassen einstelle und die von iOS bereitgestellte Schriftart "System" verwende , funktioniert alles wie erwartet, und die Schriftgrößen ändern sich je nach Größenklasse. Wenn ich eine von meiner Anwendung bereitgestellte benutzerdefinierte Schriftart verwende (ja, ich habe sie in meinem Anwendungspaket korrekt eingerichtet, da sie programmgesteuert funktioniert) und die benutzerdefinierte Schriftart auf eine Beschriftung in einem XCode 6-Storyboard setze , funktioniert dies ebenfalls wie erwartet. Wenn ich jedoch versuche, verschiedene Größen der benutzerdefinierten Schriftart für verschiedene Größenklassen im Storyboard zu verwenden, funktioniert dies plötzlich nicht mehr. Der einzige Unterschied in der Konfiguration ist die von mir gewählte Schriftart (eine benutzerdefinierte im Vergleich zur Systemschriftart). Stattdessen werden alle Schriftarten auf dem angezeigtGerät und Simulator als Standardsystemschriftart in der Standardgröße , unabhängig von der Größenklasse (und ich habe über den Debugger überprüft, dass die Systemschriftart die im Storyboard angegebene ersetzt). Grundsätzlich scheint die Größenklassenfunktion für benutzerdefinierte Schriftarten nicht zu funktionieren. Interessanterweise werden die benutzerdefinierten Schriftarten im XCode 6-Bereich "Vorschau" für den Ansichts-Controller tatsächlich angezeigt und passen die Größe richtig an: Sie funktionieren nur dann nicht mehr, wenn sie auf dem tatsächlichen iOS-System ausgeführt werden (was mich glauben lässt, dass ich sie richtig konfiguriere). .

Ich habe mehrere verschiedene benutzerdefinierte Schriftarten ausprobiert und es scheint für keine von ihnen zu funktionieren, aber es funktioniert immer, wenn ich stattdessen "System" verwende.

Wie auch immer, hat jemand anderes dieses Problem in Xcode 6 gesehen ?

Irgendwelche Ideen, ob dies ein Fehler in iOS 8, Xcode oder so ist

Mache ich falsch

Die einzige Problemumgehung, die ich gefunden habe, besteht darin, die Schriftarten weiterhin programmgesteuert festzulegen, wie ich es für etwa drei Versionen von iOS getan habe, da dies funktioniert.

Aber ich würde gerne in der Lage sein, diese Funktion zu verwenden, wenn ich sie mit benutzerdefinierten Schriftarten zum Laufen bringen könnte. Die Verwendung der Systemschriftart ist für unser Design nicht akzeptabel.


ZUSÄTZLICHE INFORMATIONEN: Ab Xcode 8.0 ist der Fehler behoben.

Mnämie
quelle
3
Ich kann bestätigen, dass dies in der App Store-Version von xCode 6.1 (6A1052d) immer noch der Fall ist.
Jodm
3
Keine Lösung, aber ich habe es geschafft, das Problem mithilfe einer Kategorie zu umgehen. Meine Kategorie UILabel + Font.h (ich habe auch eine für Schaltflächen) enthält den folgenden Code. - (void) awakeFromNib {float size = [self.font pointSize]; self.font = [UIFont fontWithName: @ "YourCustomFont" Größe: Größe]; } Auf diese Weise können wir die Größenklassen mit der Systemschriftart verwenden, um die Punktwerte in verschiedenen Größenklassen festzulegen, und die Kategorie stellt sicher, dass die richtige Schriftart festgelegt wird. Vielleicht könnten Sie es versuchen, bis Apple ein Update veröffentlicht?
Daniel Retief Fourie
2
In Xcode 6.3.1 immer noch nicht gelöst. Ich bin wütend darüber.
Wut
7
Funktioniert immer noch nicht mit Xcode 7 final. Verstehe nicht, warum Apple das Problem nicht behebt.
ernesto
5
funktioniert immer noch nicht auf Xcode 7.2 iOS 9.2
Mojtaba

Antworten:

41

Schnelle Lösung:

1) Legen Sie Schriftarten als System für Größenklassen fest

Inspektor für Etikettenattribute

2) Unterklasse UILabel und überschreibe die Methode "layoutSubviews" wie folgt:

- (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];
    }

}

Übrigens ist es eine sehr praktische Technik für ikonische Schriftarten

Rasiermesser28
quelle
Dies ist zwar eine gute Problemumgehung, wenn die in der App verwendete Schriftart dieselbe ist, aber etwas weniger praktisch, wenn Sie verschiedene Schriftarten an verschiedenen Stellen verwenden müssen, da Sie dann unterschiedliche Unterklassen usw. haben müssen. In meinem Fall habe ich bereits hatte programmatische Schriftarten eingerichtet, und es gibt viele verschiedene Möglichkeiten, wie Sie das tun können. Bei meiner Frage geht es jedoch nicht darum, wie dies programmgesteuert funktioniert, sondern darum, warum dies mit Storyboards nicht ordnungsgemäß funktioniert (es handelt sich um einen Apple-Fehler).
Mnemia
@mnemia Ich stimme zu. Mein Ziel ist es nur einen Weg zu zeigen, wie man mit diesem Fehler umgeht.
Rasiermesser 28
1
Funktioniert super. Sie müssen UILabel jedoch nicht unterordnen. Sie können diese Methode einfach in der Ansicht überschreiben, in der sich die Beschriftung befindet, und dies tun. Auf self.label.font = ...diese Weise können Sie verschiedene Schriftarten an verschiedenen Stellen verwenden.
KPM
Sie können auch eine @IBInspectable einrichten, um den Schriftartnamen zu speichern, dieselbe benutzerdefinierte Beschriftungsklasse wiederzuverwenden und verschiedene Schriftarten direkt im Storyboard anzufordern.
Craig Grummitt
Gibt es eine ähnliche Lösung für UITextField?
Chris Byatt
17

Nachdem ich alles ausprobiert hatte, entschied ich mich schließlich für eine Kombination der oben genannten Lösungen. Verwenden von 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 Mit dieser Option können Sie die Schriftgröße im Storyboard festlegen
  • Es wird ein didSetBeobachter verwendet, um die Fallstricke von layoutSubviews()(Endlosschleife für awakeFromNib()Zeilenhöhen in der dynamischen Tabellenansicht) und (siehe Kommentar von @ cocoaNoob) zu vermeiden.
  • Es werden Größenklassen anstelle der Gerätesprache verwendet, in der Hoffnung, diese letztendlich mit zu verwenden @IBDesignable
  • Funktioniert leider @IBDesignablenicht mit traitCollectiondiesem anderen Stapelartikel
  • Die Anweisung zum Wechseln der Merkmalssammlung wird UIScreen.mainScreen()nicht selfgemäß diesem Stapelartikel ausgeführt
Robert Chen
quelle
Beste Antwort, aber leider unter Voted..Thanks
Rohit Pradhan
9

Problemumgehung für UILabel: Behalten Sie für alle Größenklassen die gleiche Schriftgröße bei, ändern Sie jedoch stattdessen die Beschriftungshöhe in jeder Größenklasse entsprechend. Auf Ihrem Etikett muss Autoshrink aktiviert sein. In meinem Fall hat es gut funktioniert.

Phil
quelle
1
Ich konnte das Gleiche tun, indem ich meine Etikettenbreite in jeder Größenklasse änderte. Guter Tipp!
dmzza
1
Ich habe die Schrift nicht verkleinert, indem ich eine kleinere feste Höhe für mein UILabel festgelegt habe. Wie genau haben Sie sie zum Laufen gebracht? adjustsFontSizeToFitWidthscheint nur für die Breite zu funktionieren (was ich nicht verwenden kann, da der Text der Beschriftungen dynamisch ist).
ernesto
Ich habe das gleiche Problem mit der Anpassung an die Breite
Jules
1
Am Ende habe ich die Höhenbeschränkung des Etiketts proportional zur Höhe der Übersicht festgelegt. Das funktioniert gut, solange Sie den Parameter "Linien" des Labels in IB auf 0 setzen.
Dorian Roy
8

Dieser (und andere mit Xcode - Größenklassen zusammenhängende) Fehler verursachte mir in letzter Zeit ernsthaften Kummer, als ich eine riesige Storyboard-Datei durchgehen musste, um Dinge wegzuhacken.

Für alle anderen in dieser Position möchte ich zusätzlich zu @ razor28s Antwort etwas hinzufügen, um die Schmerzen zu lindern.

Verwenden IBInspectableSie in der Header-Datei Ihrer benutzerdefinierten Unterklasse für Ihre Laufzeitattribute. Dadurch werden diese Attribute über den "Attributes Inspector" visuell direkt über der Standardposition für die Schriftarteinstellungen zugänglich.

Anwendungsbeispiel:

@interface MyCustomLabel : UILabel

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

@end

Dies wird diese Ausgabe sehr hilfreich erzeugen:

Geben Sie hier die Bildbeschreibung ein

Ein zusätzlicher Vorteil ist, dass wir jetzt die Laufzeitattribute nicht mehr manuell für jedes Etikett hinzufügen müssen. Dies ist das, was ich dem beabsichtigten Verhalten von XCode am nächsten kommen kann. Hoffentlich ist mit iOS 9 in diesem Sommer eine richtige Lösung auf dem Weg.

Joakim
quelle
Ich habe gemäß Ihrer Anweisung hinzugefügt, aber ich kann den Zugriff auf "Attributes Inspector" nicht visuell in der xib finden. Wie kann ich das erreichen?
Darshan Kunjadiya
3

Ähnliche Lösung wie bei @ razor28, aber ich denke etwas universeller. Funktioniert auch gut mit älteren iOS-Versionen

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

Vitaly
quelle
Und natürlich können Sie im Interface Builder die Eigenschaft overrideFontName festlegen, um das Schreiben von unnötigem Code zu vermeiden
Vitaly
Dies hat bei mir nicht funktioniert, ich habe alle installierten Schriftarten innerhalb der obigen Methode aufgelistet und meine Schriftart wurde in der Variablen aufgelistet und zugewiesen, aber die Schriftartanzeige auf dem Etikett im Simulator wurde nicht geändert, und ich gehe davon aus, dass das Gerät
Jules
3

Der Fehler ist in XCode 7.0 GM weiterhin gültig.

Die Lösung von Razor28 verursacht in einigen Fällen Endlosschleifen. Meine Erfahrung war mit der Verwendung in Verbindung mit SwipeView .

Stattdessen schlage ich vor, dass Sie:

1) Unterklasse UILabel und überschreiben setFont:

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

2) Legen Sie die benutzerdefinierte Klasse Ihrer UILabels fest und legen Sie dann die Schriftgrößenklassen mithilfe der Systemschrift fest

Geben Sie hier die Bildbeschreibung ein

Foti Dim
quelle
@ Maarten1909 Beziehen Sie sich auf die Problemumgehung oder den einfachen XCode-Weg? Wenn der erste, können Sie bitte die Version angeben, damit ich versuche, sie zu reproduzieren?
Foti Dim
Es scheint, dass ich die ganze Zeit den falschen Namen der Schriftfamilie verwendet habe. Es stellt sich heraus, dass in diesem Fall die Schriftarten auf eine Systemschriftart mit einer Pint-Größe von 14,0 zurückgesetzt werden. Mein Fehler. Aber es könnte für andere nützlich sein!
Berendschot
0

Das Problem besteht weiterhin darin, dass Sie die Funktion nicht zum Festlegen von Schriftarten für verschiedene Größenklassen im Interface Builder verwenden können.

Stellen Sie einfach die Schriftart basierend auf dem gewünschten Gerät wie folgt ein:

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

Dies funktioniert perfekt auf allen Geräten.

Nirmit Dagly
quelle
0

Nichts davon hat bei mir funktioniert, aber das hat funktioniert. Sie müssen auch die Systemschriftart in IB verwenden

#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
Jules
quelle
0

Immer noch keine unterschriebene richtige Antwort. Dieser Code funktioniert gut für mich. Sie müssen zuerst die Schriftgröße für Größenklassen im Interface Builder deaktivieren. In IB können Sie eine benutzerdefinierte Schriftart verwenden.

- (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];

    }
}
Max Smirnov
quelle
0

Eine Kombination einiger der oben genannten späteren Antworten war hilfreich. So habe ich den IB-Fehler über eine Swift UILabel-Erweiterung behoben:

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)")
            }
        }
    }
}
Benjamin
quelle
-1

Ich benutze Swift, XCode 6.4. Das habe ich also getan

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. Gehe zu Designer -> Identitätsinspektor -> Setze die Klasse auf ExUILabel

  2. Gehen Sie dann im Designer zum Attributinspektor und legen Sie den Schriftartnamen fest.

Kakopappa
quelle
-1

Ich habe mir eine noch schnellere Lösung ausgedacht (ich gehe davon aus, dass Sie immer Ihre einzige benutzerdefinierte Schriftart verwenden).

Erstellen Sie eine Kategorie für UILabel und fügen Sie sie mithilfe eines fehlerhaften Storyboards mit Größenklassen und dedizierten Schriftarteneinstellungen für verschiedene Klassen in Dateien ein:

@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: http://stackoverflow.com/questions/26166737/custom-font-sizing-in-xcode6-size-classes-not-working-properly-w-custom-fonts
        self.font = [UIFont fontWithName:@"YOUR_CUSTOM_FONT_NAME" size:self.font.pointSize];
    }
}

@end

Verwenden Sie einfach Ihre benutzerdefinierten Schriftarten im Storyboard. Wenn ein fehlerhafter Interpreter stattdessen eine Systemschrift verwendet, wird diese Kategorie in Ihre benutzerdefinierte Schriftart umgeschaltet.

Heps
quelle
-1: Es ist keine gute Idee, Methoden in einer solchen Kategorie zu überschreiben. Grund: stackoverflow.com/questions/5272451/… Stattdessen sollte Swizzle (obwohl hacky) oder Unterklasse.
JRG-Entwickler
-6

Ich hatte das gleiche Problem und fand eine nicht wirklich klare, aber gute Lösung!

  1. Zuerst legen Sie die erforderliche Schriftgröße im Storyboard mit dem Systemschriftnamen fest.
  2. Dann weisen Sie diesem Label ein Tag von 100 bis 110 zu (oder mehr, aber 10 war mir in einem View Controller immer genug).
  3. Fügen Sie diesen Code dann in die Quelldatei Ihres VC ein und vergessen Sie nicht, den Schriftnamen zu ändern. Code in schnell.
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)
        }
    }
}
serg_ov
quelle
1
Verwenden Sie keine Tags. Verwenden Sie IBOutlets. Tags sind schlecht. Siehe WWDC 2015-Sitzung 231: „Wenn Sie View With Tag oder Set Tag UIView API und den Versandcode verwenden, werde ich Sie ermutigen, sich davon zu entfernen. Als Ersatz dafür deklarieren Sie Eigenschaften für Ihre Klassen, und dann haben Sie echte Verbindungen zu den Ansichten, die Sie später benötigen. “
KPM
Ich bin traurig, dass diese Lösung nicht perfekt ist, aber es funktioniert!
serg_ov
-8
  • Fügen Sie von der Anwendung bereitgestellte Schriftarten zu Ihrer App .plist hinzu
  • Fügen Sie Ihre .ttf-Datei zu Element 0 hinzu
  • benutze es [UIFont fontWithName: "example.ttf" Größe: 10]
user2612184
quelle
Dies ist keine Antwort auf dieses Problem. Natürlich können Sie benutzerdefinierte Schriftarten programmgesteuert verwenden, aber meine Frage bezieht sich auf einen Fehler in iOS 8, der verhindert, dass sich benutzerdefinierte Schriftarten je nach Größenklasse automatisch ändern.
Mnemia