自定义字体大小XCode6大小类与自定义字体无法正常工作

Xcode 6有一个新function,UILabel,UITextField和UIButton中的字体和字体大小可以根据当前设备configuration的大小等级自动设置。 例如,您可以设置UILabel在“任何宽度,高度紧凑”(例如横向上的iPhone)configuration上使用12号字体,在“普通宽度,常规高度”configuration(例如iPad上)上使用18号字体。 更多信息请点击这里:

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

这在理论上是一个非常棒的function,因为它可能不需要根据设备configuration以编程方式在UIfunction上设置不同的字体。 现在,我有一些基于设备types设置字体的条件代码,但显然这意味着我必须在整个应用程序的任何地方以编程方式设置字体。 所以我最初对这个function真的很兴奋,但是我发现它在实际使用中有一个严重的问题(可能是一个bug)。 请注意,我正在针对SDK 8进行构build,并设置了iOS 8的最低部署目标,因此这与旧版iOS的兼容性无关。

问题是这样的:如果我为不同的大小类别设置不同的字体大小,并使用iOS提供的“系统”字体,一切都按预期工作,并且字体大小根据大小类别而改变。 如果我使用由我的应用程序提供的自定义字体(是的,我已经在我的应用程序捆绑中正确设置了它,因为它以编程方式工作),并将自定义字体设置为XCode 6故事板中的标签,该function也按预期工作。 但是,当我尝试使用不同大小的自定义字体的大小不同,在故事板,它突然不起作用。 configuration唯一的区别是我select的字体(自定义的一个与系统字体)。 相反,所有字体显示在设备和模拟器上作为默认大小的默认系统字体,而不pipe大小等级如何(我通过debugging器validation它将系统字体replace为故事板中指定的实际字体) 。 所以基本上大小类function似乎是自定义字体打破。 另外,有趣的是,自定义字体实际上在视图控制器的XCode 6“预览”窗格中正确显示和resize:只有在实际的iOS系统上运行时才会停止工作(这使我认为正在configuration它正确)。

我尝试了多种不同的自定义字体,似乎并不适用于其中的任何一种,但是如果我使用“系统”,它总是有效。

无论如何,有没有人在Xcode 6中看到这个问题? 任何想法是否这是一个错误在iOS 8,Xcode,或者我做错了什么? 我发现唯一的解决方法,就像我说的,是继续以编程方式设置字体,就像我已经为大约3个版本的iOS,因为这是行不通的。 但是,如果能够使用自定义字体,我希望能够使用此function。 使用系统字体对于我们的devise是不可接受的。


附加信息:从Xcode 8.0开始,bug已修复。

快速修复:

1)将字体设置为System for size classes

标签属性检查器

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

顺便说一句,这是一个非常方便的图标字体技术

在尝试了所有的事情之后,我最终决定了上述解决scheme的组合。 使用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可以让你在Storyboard中设置字体大小
  • 它使用了一个didSet观察器,以避免layoutSubviews() (无限循环的dynamic表视图行高度)和awakeFromNib() (见@ cocoaNoob的评论)的陷阱。
  • 它使用大小类而不是设备习惯用法,希望最终在@IBDesignable使用它
  • 不幸的是,根据这个其他的堆栈文章 , @IBDesignable不能和traitCollection一起工作
  • trait集合switch语句在UIScreen.mainScreen()上执行,而不是根据这个堆栈文章自己执行

UILabel 解决方法 :在所有大小类别上保持相同的字体大小,而是在每个大小类别中相应地更改标签高度。 您的标签必须启用自动缩放。 它在我的情况很好。

这个(和其他Xcode – Size Classes相关的)bug最近让我感到非常悲伤,因为我不得不通过一个巨大的故事板文件来破解东西。

对于这个位置的其他人,我想在@ razor28的答案上添加一些内容以减轻痛苦。

在自定义子类的头文件中,使用IBInspectable作为运行时属性。 这将使这些属性可以从“属性检查器”访问,直观地位于字体设置的默认位置之上。

使用示例:

 @interface MyCustomLabel : UILabel @property (nonatomic) IBInspectable NSString *fontType; @property (nonatomic) IBInspectable CGFloat iphoneFontSize; @property (nonatomic) IBInspectable CGFloat ipadFontSize; @end 

这将非常有用地产生这个输出:

在这里输入图像说明

另外一个好处是,现在我们不必为每个标签手动添加运行时属性。 这是最接近XCode的预期行为。 希望今年夏天iOS 9能够正确地解决这个问题。

类似的@ razor28的解决scheme,但我认为更普遍一点。 此外,在旧的iOS版本上工作正常

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

该错误在XCode 7.0 GM中仍然有效。

在某些情况下,Razor28的解决scheme会导致无限循环。 我的经验是一起使用它与SwipeView 。

相反,我build议你:

1) 子类 UILabel并覆盖setFont:

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

2) 设置您的UILabels 的自定义类 ,然后使用系统字体设置字体大小类

在这里输入图像说明

问题仍然在于您不能使用该function从界面构build器为不同大小类别设置字体。

只需根据您想要的设备设置字体如下:

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

这适用于所有设备。

这些都没有为我工作,但是这样做。 您还需要在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 

仍然没有签署正确的答案。 这段代码适合我。 您必须首先在界面构build器中禁用字体大小。 在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]; } } 

上面的一些后面的答案的组合是有帮助的。 以下是我如何通过Swift UILabel扩展来解决IB错误:

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

我正在使用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. 转到devise器 – >身份检查器 – >将类设置为ExUILabel

  2. 然后去devise器中的属性检查器,并设置字体名称。

我已经提出了更快的修复(我假设你总是使用你的一个自定义字体)。

为UILabel创build一个类别,并将其包含在文件中,使用具有大小类和各种类的专用字体设置的错误画板。

 @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 

只需在故事板中使用您的自定义字体。 当越野车解释器将使用系统字体,而不是你自己的这个类别将它切换到你的自定义字体。

我有同样的问题,发现一个不是很清楚,但很好的解决scheme!

  1. 首先,您使用系统字体名称在故事板中设置所需的字体大小。
  2. 然后给这个标签分配一个从100到110的标签(或者更多,但是在一个视图控制器中,10对我来说总是足够的)。
  3. 然后把这个代码放到你的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) } } } 
  • 将应用程序提供的字体添加到您的应用程序.plist中
  • 将您的.ttf文件添加到项目0
  • 使用它[UIFont fontWithName:“example.ttf”size:10]
Interesting Posts