简体   繁体   English

Xcode 6 Size Classes 中的自定义字体大小无法与自定义字体一起正常工作

[英]Custom Font Sizing in Xcode 6 Size Classes not working properly with Custom Fonts

Xcode 6 has a new feature where fonts and font sizes in UILabel , UITextField , and UIButton can be set automatically based on the size class of the current device configuration, right in the storyboard. Xcode 6有一个新功能,其中UILabelUITextFieldUIButton中的字体字体大小可以根据当前设备配置的大小类自动设置,就在故事板中。 For example, you can set a UILabel to use font size 12 on "any width, compact height" (such as on iPhones in landscape) configurations and size 18 on "regular width, regular height" configurations (such as on iPads ).例如,您可以将UILabel设置为在“任意宽度、紧凑高度”(例如在横向的 iPhone 上)配置上使用字体大小 12,在“常规宽度、常规高度”配置(例如在iPad 上)上使用大小 18。 More information is available here:更多信息请点击这里:

developer.apple.com/size_class developer.apple.com/size_class

This is a great feature in theory because it could make it unnecessary to programmatically set different fonts on UI features based on the device configuration.从理论上讲,这是一个很棒的功能,因为它可以根据设备配置以编程方式在 UI 功能上设置不同的字体。 Right now, I have some conditional code that sets the fonts based on the device type, but obviously, that means I have to set the fonts programmatically everywhere throughout the app.现在,我有一些条件代码可以根据设备类型设置字体,但显然,这意味着我必须在整个应用程序的任何地方以编程方式设置字体。 So I was initially really excited about this feature, but I found that it has a severe problem of actual usage for me (perhaps a bug).所以一开始我对这个功能真的很兴奋,但我发现它在我的实际使用中存在严重的问题(可能是一个错误)。 Note that I am building against SDK 8 and setting a minimum deployment target of iOS 8 , so this has nothing to do with compatibility with old versions of iOS.请注意,我正在针对SDK 8构建并设置iOS 8的最低部署目标,因此这与与旧版本 iOS 的兼容性无关。

The problem is this: If I set different font sizes for different size classes and use the "System" font provided by iOS , everything works as expected, and the font sizes change based on the size class.问题是这样的:如果我为不同的大小类设置不同的字体大小并使用iOS提供的“系统”字体,一切都按预期工作,并且字体大小会根据大小类而变化。 If I use a custom font supplied by my application (yes, I have it set up correctly in my application bundle, as it works programmatically) and set the custom font to a label in an XCode 6 storyboard , that also works as expected.如果我使用我的应用程序提供的自定义字体(是的,我在我的应用程序包中正确设置了它,因为它以编程方式工作)并将自定义字体设置为XCode 6 storyboard 中标签,这也可以按预期工作。 But when I try to use different sizes of the custom font for different size classes, in the storyboard, it suddenly doesn't work.但是当我尝试为不同的大小类使用不同大小的自定义字体时,在故事板中,它突然不起作用。 The only difference in configuration is the font I've chosen (a custom one vs. the System font).配置的唯一区别是我选择的字体(自定义字体与系统字体)。 Instead, all of the fonts show up on the device and simulator as the default system font at the default size , regardless of size class (and I verified via the debugger that it is substituting the system font for the actual one specified in the storyboard).取而代之的是,所有字体都以默认 size显示在设备和模拟器上作为默认系统字体,无论大小类别如何(我通过调试器验证它正在用系统字体替换故事板中指定的实际字体) . So basically, the size class feature appears to be broken for custom fonts.所以基本上,自定义字体的大小类功能似乎被破坏了。 Also, interestingly, the custom fonts actually display and adjust size properly in the XCode 6 "Preview" pane for the view controller: it stops working only when running on the actual iOS system (which makes me think that I'm configuring it correctly).此外,有趣的是,自定义字体实际上在视图控制器的 XCode 6“预览”窗格中正确显示和调整大小:它仅在实际的 iOS 系统上运行时才停止工作(这让我认为我正在正确配置它) .

I tried multiple different custom fonts, and it doesn't seem to work for any of them, but it always works if I use "System" instead.我尝试了多种不同的自定义字体,但似乎对其中任何一种都不起作用,但如果我改用“系统”,它总是有效。

Anyway, has anyone else seen this problem in Xcode 6 ?无论如何,有没有其他人在Xcode 6 中看到过这个问题?

Any ideas on whether this is a bug in iOS 8, Xcode, or something关于这是否是 iOS 8、Xcode 或其他东西中的错误的任何想法

Am I doing wrong?我做错了吗?

The only workaround I've found, as I said, is to continue to programmatically set the fonts like I have been for about three versions of iOS because that does work.正如我所说,我找到的唯一解决方法是继续以编程方式设置字体,就像我为大约三个 iOS 版本所做的那样,因为这确实有效。

But I'd love to be able to use this feature if I could get it to work with custom fonts.但如果我可以让它与自定义字体一起工作,我很乐意能够使用这个功能。 Using the System font is not acceptable for our design.对于我们的设计,使用 System 字体是不可接受的。


ADDITIONAL INFO: As of Xcode 8.0, the bug is fixed.附加信息:从 Xcode 8.0 开始,该错误已修复。

Fast fix:快速修复:

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

标签属性检查器

2) Subclass UILabel and override "layoutSubviews" method like: 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];
    }

}

By the way, it is a very convenient technique for iconic fonts顺便说一句,这是一种非常方便的标志性字体技术

After trying everything, I eventually settled on a combination of the above solutions.在尝试了一切之后,我最终决定了上述解决方案的组合。 Using Xcode 7.2, Swift 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 lets you set the font size in the Storyboard @IBInspectable允许您在 Storyboard 中设置字体大小
  • It uses a didSet observer, to avoid the pitfalls from layoutSubviews() (infinite loop for dynamic table view row heights) and awakeFromNib() (see @cocoaNoob's comment)它使用didSet观察者,以避免layoutSubviews() (动态表视图行高的无限循环)和awakeFromNib() (见@cocoaNoob 的评论)的陷阱
  • It uses size classes rather than the device idiom, in hopes of eventually using this with @IBDesignable它使用大小类而不是设备习惯用法,希望最终与@IBDesignable一起@IBDesignable
  • Sadly, @IBDesignable doesn't work with traitCollection according to this other stack article遗憾的是,根据其他堆栈文章@IBDesignable不适用于traitCollection
  • The trait collection switch statement is performed on UIScreen.mainScreen() rather than self per this stack article trait collection switch 语句是在UIScreen.mainScreen()而不是self per this stack article上执行的

Workaround for UILabel : keep the same font size on all Size Classes, but instead change your label height accordingly in each Size Class. UILabel解决方法:在所有尺寸类别上保持相同的字体大小,但在每个尺寸类别中相应地更改标签高度。 Your label must have autoshrink enabled.您的标签必须启用自动收缩。 It worked nicely in my case.在我的情况下它工作得很好。

This (and other Xcode - Size Classes related) bug caused me some serious grief recently as I had to go through a huge storyboard file hacking things away.这个(和其他 Xcode - Size Classes 相关的)错误最近让我感到非常悲伤,因为我不得不通过一个巨大的故事板文件来破解一些东西。

For anyone else in this position, I'd like to add something on top of @razor28's answer to ease the pain.对于这个职位的其他任何人,我想在@razor28 的答案之上添加一些东西以减轻痛苦。

In the header file of your custom subclass, use IBInspectable for your runtime attributes.在自定义子类的头文件中,将IBInspectable用于运行时属性。 This will make these attributes accessible from the "Attributes Inspector", visually right above the default position for font settings.这将使这些属性可以从“属性检查器”访问,直观地位于字体设置的默认位置正上方。

Example use:使用示例:

@interface MyCustomLabel : UILabel

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

@end

This will very helpfully produce this output:这将非常有助于产生以下输出:

在此处输入图片说明

An added benefit is that now we don't have to add the runtime attributes manually for each label.一个额外的好处是,现在我们不必为每个标签手动添加运行时属性。 This is the closest I could get to XCode's intended behaviour.这是我能得到的最接近 XCode 预期行为的方法。 Hopefully a proper fix is on its way with iOS 9 this summer.希望今年夏天能够在 iOS 9 上进行适当的修复。

Similar solution to @razor28's one but I think a little more universal.与@razor28 的解决方案类似,但我认为更通用一些。 Also, works fine on older iOS versions此外,在较旧的 iOS 版本上运行良好

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

The bug is still valid in XCode 7.0 GM.该错误在 XCode 7.0 GM 中仍然有效。

Razor28's solution causes infinite loops in some cases. Razor28 的解决方案在某些情况下会导致无限循环。 My experience has been with using it in conjunction with SwipeView .我的经验是将它与SwipeView结合使用。

Instead, I suggest that you:相反,我建议您:

1) Subclass UILabel and override setFont: 1)子类化UILabel 并覆盖setFont:

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

2) Set the custom class of your UILabels and then set the font size classes by using System font 2)设置UILabels的自定义类,然后使用 System font设置字体大小类

在此处输入图片说明

The problem is still there that you cannot use the feature to set Fonts for different size classes from interface builder.问题仍然存在,您无法使用该功能为界面构建器中的不同大小类设置字体。

Just set font based on the device you want just like below:只需根据您想要的设备设置字体,如下所示:

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

This works perfectly on all devices.这适用于所有设备。

None of these worked for me, but this did.这些都不适合我,但确实如此。 You also need to use the system font in IB您还需要使用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

Still no signed right answer.仍然没有签名正确答案。 This code works fine for me.这段代码对我来说很好用。 You must disable font size for size classes in interface builder first.您必须首先在界面构建器中禁用大小类的字体大小。 In IB you can use custom font.在 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];

    }
}

A combination of some of the later answers above were helpful.上面一些后来的答案的组合是有帮助的。 Here's how I solved the IB bug via a Swift UILabel extension:以下是我通过 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)")
            }
        }
    }
}

I am using Swift, XCode 6.4.我正在使用 Swift,XCode 6.4。 So this is what I did所以这就是我所做的

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 -> Identity Inspector -> Set the class to ExUILabel转到设计器 -> 身份检查器 -> 将类设置为 ExUILabel

  2. Then go to Attribute inspector in designer and set the font name.然后转到设计器中的属性检查器并设置字体名称。

I've come up with even faster fix (I assume you always use your one custom font).我想出了更快的修复方法(我假设您总是使用一种自定义字体)。

Create a category for UILabel and include in files using buggy storyboard with size classes and dedicated font setting for various classes:为 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

Just use your custom fonts in storyboard.只需在故事板中使用您的自定义字体。 When buggy interpreter will use system font instead your own this category will switch it to your custom font.当错误解释器将使用系统字体而不是您自己的字体时,此类别会将其切换为您的自定义字体。

I had the same problem and found one not really clear, but fine solution!我遇到了同样的问题,找到了一个不太清楚但很好的解决方案!

  1. First you set the required font size in storyboard with system font name.首先,您使用系统字体名称在故事板中设置所需的字体大小。
  2. Then to this label you assign a tag from 100 to 110 (or more, but 10 was always enough for me in one view controller).然后给这个标签分配一个从 100 到 110 的标签(或更多,但在一个视图控制器中 10 对我来说总是足够的)。
  3. Then put this code to your VC's source file and don't forget to change font name.然后将此代码放入 VC 的源文件中,不要忘记更改字体名称。 Code in swift.快速编码。
 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) } } }
  • add Fonts provided by application into your app .plist将应用程序提供的字体添加到您的应用程序 .plist 中
  • add your .ttf file to item 0将您的 .ttf 文件添加到项目 0
  • use it [UIFont fontWithName:"example.ttf" size:10]使用它 [UIFont fontWithName:"example.ttf" size:10]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM