Налаштування розміру шрифту в класах розмірів Xcode 6, які не працюють належним чином із спеціальними шрифтами


104

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

developer.apple.com/size_class

Ця теорія є чудовою особливістю, оскільки це може змусити програмувати різні шрифти для функцій інтерфейсу на основі конфігурації пристрою. Зараз у мене є якийсь умовний код, який встановлює шрифти на основі типу пристрою, але, очевидно, це означає, що мені потрібно встановлювати шрифти програмно скрізь у всьому додатку. Тож спочатку я був дуже в захваті від цієї функції, але я виявив, що вона має серйозну проблему фактичного використання для мене (можливо, помилка). Зауважте, що я будую проти SDK 8 і встановлюю мінімальну ціль розгортання iOS 8 , тому це не має нічого спільного з сумісністю зі старими версіями iOS.

Проблема полягає в наступному: Якщо я встановив різні розміри шрифту для різних класів розмірів і використовую шрифт "Система", наданий iOS , все працює як очікується, а розміри шрифту змінюються залежно від класу розмірів. Якщо я використовую нестандартний шрифт, наданий моєю програмою (так, у мене він встановлений правильно в моєму пакеті програм, оскільки він працює програмно) і встановити спеціальний шрифт як мітку на дошці розкадрівників XCode 6 , яка також працює як очікувалося. Але коли я намагаюся використовувати різний розмір нестандартного шрифту для різних класів розмірів, у розгортці це раптом не виходить. Єдина відмінність конфігурації - це вибраний вами шрифт (спеціальний шрифт проти системного шрифту). Натомість усі шрифти відображаються напристрій та симулятор як шрифт за замовчуванням системного розміру за замовчуванням , незалежно від класу розміру (і я перевірив за допомогою налагоджувача, що він замінює шрифт системи на фактичний, вказаний на дошці розкадрування). Таким чином, функція класу розмірів, як видається, порушена для користувацьких шрифтів. Також цікаво, що спеціальні шрифти фактично відображають та регулюють розмір належним чином на панелі XCode 6 "Попередній перегляд" для контролера перегляду: він перестає працювати лише під час роботи в реальній системі iOS (що змушує мене думати, що я правильно його налаштовую) .

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

У будь-якому разі, хтось ще бачив цю проблему в Xcode 6 ?

Будь-які ідеї щодо того, чи це помилка в iOS 8, Xcode чи щось таке

Я помиляюся?

Як я вже сказав, єдине вирішення, яке я знайшов, - це продовжувати програмно встановлювати шрифти, як я був для приблизно трьох версій iOS, тому що це працює.

Але я хотів би мати можливість використовувати цю функцію, якби я міг змусити її працювати зі спеціальними шрифтами. Використання шрифту System не прийнятно для нашого дизайну.


ДОДАТКОВІ ІНФОРМАЦІЇ: Станом на Xcode 8.0 помилка виправлена.


3
Я можу підтвердити, що це все-таки у випуску магазину додатків xCode 6.1 (6A1052d).
jodm

3
Не рішення, але мені вдалося обійти проблему за допомогою категорії. Моя категорія UILabel + Font.h (у мене також є кнопки) містить наступний код. - (void) awakeFromNib {float size = [self.font pointSize]; self.font = [UIFont fontWithName: @ "YourCustomFont" розмір: розмір]; } Отже, це дозволяє нам використовувати класи розмірів із шрифтом System для встановлення точкових значень у різних класах розмірів, і категорія забезпечує встановлення правильного шрифту. Можливо, ви могли б подумати, поки Apple не випустить оновлення?
Даніель Ретьєф Фурі

2
Досі не вирішено в Xcode 6.3.1. Я злий на це.
Фурія

7
Досі не працює з Xcode 7 final. Не розумію, чому Apple цього не виправляє.
ernesto

5
досі не працює на Xcode 7.2 iOS 9.2
Mojtaba

Відповіді:


41

Швидке виправлення:

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

Мітки атрибути інспектора

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

}

До речі, це дуже зручна техніка для знакових шрифтів


Хоча це вдале вирішення, якщо шрифт, який використовується в додатку, однаковий, це трохи менш зручно, якщо вам потрібно використовувати різні шрифти в різних місцях, тому що тоді у вас повинні бути різні підкласи тощо. У моєму випадку я вже у вас були програмні шрифти для налаштування, і ви можете зробити це багато різних способів. Але суть мого питання не в тому, щоб запитати, як це зробити програмно: це запитати, чому це не працює належним чином за допомогою Storyboards (це помилка Apple).
мнемія

@mnemia Я згоден. Моя мета - просто показати один із способів поводження з цим клопом.
razor28

1
Чудово працює. Не потрібно підкласи UILabel, можливо, ви можете просто перекрити цей метод у вікні, що містить мітку, і self.label.font = ...таким чином ви можете використовувати різні шрифти в різних місцях.
КПМ

Або ви можете налаштувати @IBInspectable, щоб зберегти ім'я шрифту, повторно використовувати той самий спеціальний клас міток та запитувати різні шрифти безпосередньо у дошці розкадрування.
Крейг Груммітт

Чи є подібне рішення для UITextField?
Кріс Баятт

17

Перепробувавши все, я врешті-решт зупинився на поєднанні вищезазначених рішень. Використовуючи 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на цій статті стека, а не на цій статті

Найкраща відповідь, Але, на жаль, проголосували ... Дякую
Rohit

9

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


1
Я зміг зробити те ж саме, змінивши ширину мітки у кожному розмірному класі. Гарна порада!
dmzza

1
Мені не вдалося зменшити шрифт, встановивши меншу фіксовану висоту для мого UILabel, як саме ви змусили його працювати? adjustsFontSizeToFitWidthздається, працює лише на ширину (яку я не можу використовувати, оскільки текст міток динамічний).
ernesto

У мене те саме питання з коригуванням відповідно до ширини
Jules

1
Я в кінцевому підсумку встановив обмеження висоти мітки пропорційно висоті огляду. Це добре працює, якщо ви встановите параметр "Лінії" мітки в ІБ на 0.
Доріан Рой

8

Ця помилка (та інші пов’язані з класом розміру Xcode) завдала мені серйозного горя останнім часом, оскільки мені довелося пережити величезний файл розкадрівки, щоб зламати речі.

Для всіх, хто перебуває на цій посаді, я хотів би додати щось на відповідь @ razor28, щоб полегшити біль.

У файлі заголовка вашого спеціального підкласу використовуйте IBInspectableдля атрибутів виконання. Це зробить доступними ці атрибути у "Ревізора атрибутів", візуально праворуч над положенням за замовчуванням для налаштувань шрифту.

Приклад використання:

@interface MyCustomLabel : UILabel

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

@end

Це дуже корисно дасть такий результат:

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

Додатковою перевагою є те, що тепер нам не потрібно додавати атрибути виконання вручну для кожної мітки. Це найближче, що я міг дістатися до передбачуваної поведінки XCode. Сподіваємось, це літо на шляху належного виправлення з iOS 9.


Я додав відповідно до вашої інструкції, але я не в змозі знайти візуальний доступ до інспектора атрибутів у xib, то як це досягти?
Даршан Кунядія

3

Подібне рішення до @ razor28, але я думаю, трохи більш універсальний. Також відмінно працює на старих версіях iOS

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


І точно, ви можете встановити властивість overrideFontName в Interface Builder, що дозволяє уникнути написання непотрібного коду
Віталій

Це не спрацювало для мене, я перерахував усі встановлені шрифти в рамках вищевказаного методу, і мій шрифт був перелічений та призначений у змінній, але не змінив показ шрифту в мітці на тренажері, і я припускаю, що пристрій
Jules

3

Помилка все ще діє в XCode 7.0 GM.

Рішення Razor28 в деяких випадках викликає нескінченні петлі. Мій досвід був із його використанням спільно з SwipeView .

Натомість я пропоную вам:

1) Підклас UILabel і переопределити набірFont:

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

2) Встановіть спеціальний клас своїх UILabels та встановіть класи розмірів шрифту за допомогою шрифту System

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


@ Maarten1909 Ви маєте на увазі спосіб вирішення чи простий шлях XCode? Якщо ви можете першим, будь ласка, вкажіть версію, щоб спробувати її відтворити?
Foti Dim

Здається, я весь час використовував неправильне прізвище шрифту. Виявляється, у такому випадку шрифти скидаються на системний шрифт розміром 14,0 пінта. Моє ліжко. Але це може бути корисно іншим!
Berendschot

0

Проблема все ще існує в тому, що ви не можете використовувати цю функцію для встановлення шрифтів для різних класів розмірів від конструктора інтерфейсів.

Просто встановіть шрифт залежно від потрібного пристрою, як нижче:

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

Це чудово працює на всіх пристроях.


0

Жодне з них не працювало для мене, але це було. Також потрібно використовувати системний шрифт у 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

Досі немає підписаної правильної відповіді. Цей код добре працює для мене. Потрібно спочатку вимкнути розмір шрифту для класів розмірів у конструкторі інтерфейсів. У 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];

    }
}

0

Поєднання деяких пізніших відповідей вище було корисним. Ось як я вирішив помилку 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)")
            }
        }
    }
}

-1

Я використовую 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)
        }
    }
  1. Goto Designer -> Інспектор ідентичності -> Встановіть клас ExUILabel

  2. Потім перейдіть до інспектора атрибутів у дизайнері та встановіть назву шрифту.


-1

Я придумав ще швидше виправлення (я припускаю, що ви завжди використовуєте один власний шрифт).

Створіть категорію для 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

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


-1: Недоцільно переосмислити методи у такій категорії. Причина: stackoverflow.com/questions/5272451 / ... Замість цього слід Swizzle (хоча Hacky) або підклас.
JRG-Developer

-6

У мене була та сама проблема, і я знайшов одне не дуже зрозуміле, але прекрасне рішення!

  1. Спочатку ви встановлюєте необхідний розмір шрифту в дошці розкадрівки із назвою шрифту системи.
  2. Потім до цієї мітки ви присвоюєте тег від 100 до 110 (або більше, але 10 мені завжди вистачало в одному контролері перегляду).
  3. Потім поставте цей код у вихідний файл вашого ВК і не забудьте змінити ім'я шрифту. Код швидко.
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)
        }
    }
}

1
Не використовуйте теги. Використовуйте IBOutlets. Теги погані. Див. Сесію WWDC 2015 231: "Якщо ви використовуєте View with Tag або Set Tag UIView API та код доставки, я рекомендую вам відійти від цього. В якості заміни цьому оголосіть властивості у своїх класах, і тоді ви матимете реальне підключення до тих поглядів, які вам потрібні пізніше ».
КПМ

Мені сумно, що це рішення не ідеальне, але воно працює!
serg_ov

-8
  • додайте шрифти, надані додатком, у свій .plist додаток
  • додайте файл .ttf до пункту 0
  • використовувати його [UIFont fontWithName: "example.ttf" розмір: 10]

Це не відповідь на цю проблему. Очевидно, що ви можете користувальницькі шрифти використовувати програмно, але те, на що йдеться у моєму питанні, - це помилка в iOS 8, яка запобігає автоматичним змінам спеціальних шрифтів залежно від класу розміру.
мнемія
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.