Настраиваемый размер шрифта в классах размера Xcode 6 не работает должным образом с настраиваемыми шрифтами

Xcode 6 имеет новую функцию, в которой шрифты и размеры шрифтов в UILabel, UITextField и UIButton могут быть установлены автоматически на основе класса размера текущей конфигурации устройства прямо в раскадровке. Например, вы можете установить UILabel для использования размера шрифта 12 на "любой ширине, компактной высоте" (например, на iPhone в ландшафтном дизайне) и размере 18 на конфигурациях "обычной ширины, обычной высоты" (например, на iPads). Дополнительная информация доступна здесь:

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

Это действительно замечательная функция в теории, потому что это может сделать ненужным программный набор различных шрифтов для функций пользовательского интерфейса на основе конфигурации устройства. Прямо сейчас у меня есть условный код, который устанавливает шрифты на основе типа устройства, но, очевидно, это означает, что я должен устанавливать шрифты программно повсюду в приложении. Поэтому я действительно был в восторге от этой функции, но я обнаружил, что у меня есть серьезная проблема в фактическом использовании для меня (возможно, ошибка). Обратите внимание, что я строю против SDK 8 и устанавливаю минимальную цель развертывания iOS 8, поэтому это не имеет ничего общего с совместимостью со старыми версиями iOS.

Проблема заключается в следующем: Если я устанавливаю разные размеры шрифтов для разных классов размеров и использую шрифт "System", предоставляемый iOS, все работает так, как ожидалось, и размеры шрифта меняются в зависимости от класса размера. Если я использую специальный шрифт, предоставляемый моим приложением (да, я правильно настроил его в своем пакете приложений, так как он работает программно) и установите пользовательский шрифт на метку в раскадровке XCode 6, которая также работает так, как ожидалось. Но когда я пытаюсь использовать разные размеры пользовательского шрифта для разных классов размера, в раскадровке он внезапно не работает. Единственная разница в конфигурации - это выбранный мной шрифт (пользовательский вариант по сравнению с системным шрифтом). Вместо этого все шрифты отображаются на устройстве и симуляторе как стандартный системный шрифт по умолчанию, независимо от класса размера (и я проверил через отладчик, что он заменяет системный шрифт для фактического, указанного в раскадровке), Таким образом, в основном функция класса размера не работает для пользовательских шрифтов. Кроме того, интересно, что пользовательские шрифты фактически отображают и правильно регулируют размер на панели "Просмотр" XCode 6 для контроллера вида: он работает только при запуске в реальной системе iOS, которая перестает работать (что заставляет меня думать, что я настраиваю его правильно).

Я попробовал несколько разных пользовательских шрифтов и, похоже, не работает ни для одного из них, но всегда работает, если вместо этого использовать "Систему".

В любом случае, кто-нибудь еще видел эту проблему в Xcode 6? Любые идеи о том, является ли это ошибкой в ​​iOS 8, Xcode или что-то, что я делаю неправильно? Единственное обходное решение, которое я нашел, как я уже сказал, заключается в том, чтобы продолжать программно устанавливать шрифты, как я был примерно для 3-х версий iOS, потому что это действительно работает. Но я бы хотел использовать эту функцию, если бы мог заставить ее работать с пользовательскими шрифтами. Использование шрифта System неприемлемо для нашего дизайна.


ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Начиная с Xcode 8.0 исправлена ​​ошибка.

Ответ 1

Быстрое исправление:

1) Установить шрифты как систему для классов размера

Label attributes inspector

2) Подкласс UILabel и переопределить метод layoutSubviews, например:

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

}

Кстати, это очень удобная техника для знаковых шрифтов

Ответ 2

После всех попыток, я в конце концов решил использовать комбинацию вышеупомянутых решений. Использование 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 позволяет установить размер шрифта в раскадровке
  • Он использует наблюдателя didSet, чтобы избежать ошибок из layoutSubviews() (бесконечный цикл для динамических высот строк таблицы таблиц) и awakeFromNib() (см. комментарий @cocoaNoob)
  • В нем используются классы размеров, а не идиома устройства, в надежде, что в конечном итоге это будет с помощью @IBDesignable
  • К сожалению, @IBDesignable не работает с traitCollection в соответствии с этой другой статьей стека
  • Оператор переключения коллекции признаков выполняется на UIScreen.mainScreen(), а не self за эту статью .

Ответ 3

Обходной путь для UILabel: сохраните одинаковый размер шрифта во всех классах классов, но вместо этого измените высоту своей метки соответственно в каждом классе размеров. У вашей метки должен быть включен автозапуск. Это хорошо работало в моем случае.

Ответ 4

Этот (и другие связанные с Xcode-Size классы) ошибка в последнее время вызвала у меня серьезное горе, поскольку мне пришлось пройти через огромный файл раскадровки, взломав вещи.

Для кого-либо еще в этом положении я хотел бы добавить что-то поверх ответа @razor28, чтобы облегчить боль.

В файле заголовка вашего пользовательского подкласса используйте IBInspectable для ваших атрибутов времени выполнения. Это приведет к тому, что эти атрибуты будут доступны из "Attributes Inspector", визуально расположенного над позицией по умолчанию для настроек шрифта.

Пример использования:

@interface MyCustomLabel : UILabel

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

@end

Это будет очень полезно производить этот вывод:

enter image description here

Дополнительным преимуществом является то, что теперь нам не нужно добавлять атрибуты runtime вручную для каждой метки. Это самый близкий подход к XCode. Надеюсь, правильное исправление находится на пути к iOS 9 этим летом.

Ответ 5

Аналогичное решение для @razor28 одно, но я думаю немного более универсальным. Кроме того, отлично работает в более старых версиях iOS

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

Ответ 6

Ошибка остается в XCode 7.0 GM.

В некоторых случаях решение Razor28 вызывает бесконечные циклы. Мой опыт заключается в использовании его в сочетании с SwipeView.

Вместо этого я предлагаю вам:

1) Подкласс UILabel и переопределить setFont:

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

2) Задайте пользовательский класс ваших UILabels, а затем установите классы размера шрифта, используя System font

введите описание изображения здесь

Ответ 7

Проблема в том, что вы не можете использовать эту функцию для установки шрифтов для разных классов размера из конструктора интерфейса.

Просто установите шрифт на основе устройства, которое вы хотите, как показано ниже:

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

Это отлично работает на всех устройствах.

Ответ 8

Никто из них не работал у меня, но это было так. Вам также необходимо использовать системный шрифт в 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

Ответ 9

По-прежнему нет подписанного правильного ответа. Этот код отлично подходит для меня. Сначала вы должны отключить размер шрифта для классов размера в построителе интерфейса. В IB вы можете использовать пользовательский шрифт.

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

    }
}

Ответ 10

Комбинация некоторых из более поздних ответов выше была полезной. Здесь, как я решил ошибку IB через расширение Swift UILabel:

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

Ответ 11

Я использую Swift, XCode 6.4. Так вот что я сделал

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)
        }
    }
  • Goto Designer → Identity Inspector → Установить класс в ExUILabel

  • Затем перейдите в инспектор атрибутов в конструкторе и задайте имя шрифта.

Ответ 12

Я придумал еще более быстрое исправление (я предполагаю, что вы всегда используете свой собственный шрифт).

Создайте категорию для UILabel и включите в файлы, используя баггистую раскадровку с размерами и специальными настройками шрифта для различных классов:

@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

Просто используйте свои собственные шрифты в раскадровке. Когда глючный интерпретатор будет использовать системный шрифт, вместо этого ваша собственная эта категория переключит его на свой собственный шрифт.

Ответ 13

У меня была такая же проблема, и я нашел не очень ясное, но прекрасное решение!

  • Сначала вы установили требуемый размер шрифта в раскадровке с именем системного шрифта.
  • Затем на этот ярлык вы назначаете тег от 100 до 110 (или больше, но 10 всегда были достаточно для меня в одном контроллере представления).
  • Затем поместите этот код в исходный файл VC и не забудьте изменить имя шрифта. Код быстро.
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)
        }
    }
}

Ответ 14

  • добавить шрифты, предоставленные приложением в ваше приложение .plist
  • добавьте ваш .ttf файл в элемент 0
  • использовать его [UIFont fontWithName: "example.ttf" size: 10]