Настраиваемый размер шрифта в классах размера 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)
}
}
Ответ 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]