104

Xcode 6有一个新功能,其中字体字体大小UILabelUITextField和 ,并且UIButton可以根据当前设备配置的大小类别自动设置,就在故事板中。例如,您可以将 a 设置为UILabel在“任意宽度、紧凑高度”(例如横向 iPhone)配置中使用字体大小 12,在“常规宽度、常规高度”配置(例如在iPad上)使用字体大小 18。更多信息请点击这里:

developer.apple.com/size_class

这在理论上是一个很棒的功能,因为它可以使您无需根据设备配置以编程方式在 UI 功能上设置不同的字体。现在,我有一些条件代码可以根据设备类型设置字体,但显然,这意味着我必须在整个应用程序的任何地方以编程方式设置字体。所以我一开始对这个功能非常兴奋,但我发现它对我来说在实际使用中存在严重问题(可能是一个错误)。请注意,我正在针对SDK 8构建并设置iOS 8的最小部署目标,因此这与与旧版本 iOS 的兼容性无关。

问题是这样的: 如果我为不同的大小类设置不同的字体大小并使用iOS提供的“系统”字体,一切都会按预期工作,并且字体大小会根据大小类而变化。如果我使用我的应用程序提供的自定义字体(是的,我在我的应用程序包中正确设置了它,因为它以编程方式工作)并将自定义字体设置为XCode 6 故事板中的标签,这也可以按预期工作。但是当我尝试为不同大小的类使用不同大小的自定义字体时,在情节提要中,它突然不起作用。配置的唯一区别是我选择的字体(自定义字体与系统字体)。相反,所有字体都显示在设备和模拟器作为默认大小默认系统字体,不管大小类(我通过调试器验证它正在用系统字体替换情节提要中指定的实际字体)。所以基本上,自定义字体的大小类功能似乎被破坏了。此外,有趣的是,自定义字体实际上在视图控制器的 XCode 6“预览”窗格中正确显示和调整大小:它仅在实际 iOS 系统上运行时才停止工作(这让我认为我正在正确配置它) .

我尝试了多种不同的自定义字体,但似乎对它们中的任何一种都不起作用,但如果我使用“系统”来代替,它总是有效的。

无论如何,有没有其他人在Xcode 6中看到过这个问题?

关于这是否是 iOS 8、Xcode 或其他错误的任何想法

我做错了吗?

正如我所说,我发现的唯一解决方法是继续以编程方式设置字体,就像我在大约三个 iOS 版本中所做的那样,因为这确实有效。

但如果我可以让它与自定义字体一起使用,我很想能够使用这个功能。我们的设计不接受使用系统字体。


附加信息: 从 Xcode 8.0 开始,该错误已修复。

4

14 回答 14

41

快速修复:

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

}

顺便说一句,对于标志性字体来说,这是一种非常方便的技术

于 2015-01-22T09:43:53.283 回答
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
  • 可悲的是,根据this other stack article@IBDesignable不适用于traitCollection
  • 特征集合 switch 语句是在此堆栈文章上UIScreen.mainScreen()而不是self根据此堆栈文章执行的
于 2016-01-07T23:38:08.080 回答
9

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

于 2015-03-20T08:12:43.617 回答
8

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

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

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

示例使用:

@interface MyCustomLabel : UILabel

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

@end

这将非常有助于产生以下输出:

在此处输入图像描述

另一个好处是,现在我们不必为每个标签手动添加运行时属性。这是我最接近 XCode 预期行为的方法。希望今年夏天的 iOS 9 能够进行适当的修复。

于 2015-06-03T18:22:56.967 回答
3

与@razor28 的解决方案类似,但我认为更通用一点。此外,在较旧的 iOS 版本上也能正常工作

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

于 2015-04-02T20:00:26.110 回答
3

该错误在 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的自定义类,然后使用系统字体设置字体大小类

在此处输入图像描述

于 2015-09-11T09:30:34.463 回答
0

上面一些后来的答案的组合很有帮助。以下是我通过 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)")
            }
        }
    }
}
于 2016-07-06T20:57:39.273 回答
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];

    }
}
于 2016-06-19T10:21:46.547 回答
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]]; 
}

这适用于所有设备。

于 2015-10-28T06:54:53.367 回答
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
于 2015-11-13T09:15:25.673 回答
-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

只需在情节提要中使用您的自定义字体。当有缺陷的解释器将使用系统字体而不是您自己的时,此类别会将其切换为您的自定义字体。

于 2016-05-10T10:19:31.290 回答
-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. 转到 Designer -> Identity Inspector -> 将类设置为 ExUILabel

  2. 然后转到设计器中的属性检查器并设置字体名称。

于 2015-09-21T16:37:04.533 回答
-6

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

  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)
        }
    }
}
于 2015-06-15T13:44:26.587 回答
-8
  • 将应用程序提供的字体添加到您的应用程序 .plist
  • 将您的 .ttf 文件添加到项目 0
  • 使用它 [UIFont fontWithName:"example.ttf" size:10]
于 2015-01-19T06:48:59.467 回答