首页 文章

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

提问于
浏览
101

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

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

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

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

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

无论如何,还有其他人在Xcode 6中看到过这个问题吗?关于这是否是iOS 8,Xcode中的错误或者我做错了什么的任何想法?我发现,我发现的唯一解决方法是继续以编程方式设置字体,就像我已经为大约3个版本的iOS一样,因为这确实有效 . 但我希望能够使用此功能,如果我可以使用自定义字体 . 我们的设计不接受使用System字体 .


附加信息:从Xcode 8.0开始,修复了错误 .

14 回答

  • 17

    Fast fix:

    1)将字体设置为System的尺寸类

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

    顺便说一下,它是一种非常方便的标志性字体技术

  • -6

    在尝试了一切之后,我最终确定了上述解决方案的组合 . 使用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() (动态表视图行高的无限循环)和 awakeFromNib() (参见@cocoaNoob的评论)中的陷阱

    • 它使用大小类而不是设备习语,希望最终使用 @IBDesignable


    • 特征集合开关语句在 UIScreen.mainScreen() 而不是 self 上执行stack article
  • 40

    Workaround for UILabel :在所有Size Classes上保持相同的字体大小,而是在每个Size Class中相应地更改标签高度 . 您的标签必须启用自动收缩功能 . 在我的情况下它很好用 .

  • 3

    这个(和其他Xcode - Size Classes相关的)错误最近引起了我一些严重的悲痛,因为我不得不通过一个巨大的故事板文件来攻击事情 .

    对于这个职位上的其他任何人,我想在@ 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

    另一个好处是,现在我们不必为每个标签手动添加运行时属性 . 这是我最接近XCode的预期行为 . 希望正确的解决方案正在使用iOS 9夏季 .

  • -1

    类似@ razor28的解决方案,但我认为更普遍 . 此外,在较旧的iOS版本上工作正常

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

  • 0

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

    在某些情况下,Razor28的解决方案会导致无限循环 . 我的经验是将它与SwipeView结合使用 .

    相反,我建议你:

    1) Subclass UILabel并覆盖 setFont:

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

    2) Set the custom class 您的UILabel,然后 set the font size classes 使用系统字体

    enter image description here

  • 9

    问题仍然存在,您无法使用该功能为界面构建器中的不同大小类设置字体 .

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

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

    这适用于所有设备 .

  • 2

    这些都不适合我,但确实如此 . 您还需要在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

    上面一些后面的答案的组合是有帮助的 . 这是我通过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)")
                }
            }
        }
    }
    
  • 0

    我正在使用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)
            }
        }
    
    • 转到设计器 - > Identity Inspector - >将类设置为ExUILabel

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

  • -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
    

    只需在故事板中使用自定义字体即可 . 当有缺陷的解释器将使用系统字体而不是您自己的类别将其切换为您的自定义字体 .

  • 8

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

    • 首先,在storyboard中使用系统字体名称设置所需的字体大小 .

    • 然后在此标签上分配一个100到110的标签(或更多,但在一个视图控制器中,10对我来说总是足够) .

    • 然后将此代码放入VC 's source file and don' t忘记更改字体名称 . 快速编码 .

    覆盖func viewDidLayoutSubviews(){
    因为我在100 ... 110 {
    如果让label = view.viewWithTag(i)为? UILabel

    }
    }

  • -8
    • 将应用程序提供的字体添加到您的应用.plist中

    • 将.ttf文件添加到第0项

    • 使用它[UIFont fontWithName:"example.ttf" size:10]

相关问题