[英]Custom Font Sizing in Xcode 6 Size Classes not working properly with Custom Fonts
Xcode 6有一个新功能,其中UILabel
、 UITextField
和UIButton
中的字体和字体大小可以根据当前设备配置的大小类自动设置,就在故事板中。 例如,您可以将UILabel
设置为在“任意宽度、紧凑高度”(例如在横向的 iPhone 上)配置上使用字体大小 12,在“常规宽度、常规高度”配置(例如在iPad 上)上使用大小 18。 更多信息请点击这里:
developer.apple.com/size_class
从理论上讲,这是一个很棒的功能,因为它可以根据设备配置以编程方式在 UI 功能上设置不同的字体。 现在,我有一些条件代码可以根据设备类型设置字体,但显然,这意味着我必须在整个应用程序的任何地方以编程方式设置字体。 所以一开始我对这个功能真的很兴奋,但我发现它在我的实际使用中存在严重的问题(可能是一个错误)。 请注意,我正在针对SDK 8构建并设置iOS 8的最低部署目标,因此这与与旧版本 iOS 的兼容性无关。
问题是这样的:如果我为不同的大小类设置不同的字体大小并使用iOS提供的“系统”字体,一切都按预期工作,并且字体大小会根据大小类而变化。 如果我使用我的应用程序提供的自定义字体(是的,我在我的应用程序包中正确设置了它,因为它以编程方式工作)并将自定义字体设置为XCode 6 storyboard 中的标签,这也可以按预期工作。 但是当我尝试为不同的大小类使用不同大小的自定义字体时,在故事板中,它突然不起作用。 配置的唯一区别是我选择的字体(自定义字体与系统字体)。 取而代之的是,所有字体都以默认 size显示在设备和模拟器上作为默认系统字体,无论大小类别如何(我通过调试器验证它正在用系统字体替换故事板中指定的实际字体) . 所以基本上,自定义字体的大小类功能似乎被破坏了。 此外,有趣的是,自定义字体实际上在视图控制器的 XCode 6“预览”窗格中正确显示和调整大小:它仅在实际的 iOS 系统上运行时才停止工作(这让我认为我正在正确配置它) .
我尝试了多种不同的自定义字体,但似乎对其中任何一种都不起作用,但如果我改用“系统”,它总是有效。
无论如何,有没有其他人在Xcode 6 中看到过这个问题?
关于这是否是 iOS 8、Xcode 或其他东西中的错误的任何想法
我做错了吗?
正如我所说,我找到的唯一解决方法是继续以编程方式设置字体,就像我为大约三个 iOS 版本所做的那样,因为这确实有效。
但如果我可以让它与自定义字体一起工作,我很乐意能够使用这个功能。 对于我们的设计,使用 System 字体是不可接受的。
附加信息:从 Xcode 8.0 开始,该错误已修复。
快速修复:
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];
}
}
顺便说一句,这是一种非常方便的标志性字体技术
在尝试了一切之后,我最终决定了上述解决方案的组合。 使用 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
一起@IBDesignable
@IBDesignable
不适用于traitCollection
UIScreen.mainScreen()
而不是self
per this stack article上执行的 UILabel
解决方法:在所有尺寸类别上保持相同的字体大小,但在每个尺寸类别中相应地更改标签高度。 您的标签必须启用自动收缩。 在我的情况下它工作得很好。
这个(和其他 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 上进行适当的修复。
与@razor28 的解决方案类似,但我认为更通用一些。 此外,在较旧的 iOS 版本上运行良好
该错误在 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设置字体大小类
问题仍然存在,您无法使用该功能为界面构建器中的不同大小类设置字体。
只需根据您想要的设备设置字体,如下所示:
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
仍然没有签名正确答案。 这段代码对我来说很好用。 您必须首先在界面构建器中禁用大小类的字体大小。 在 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)
}
}
转到设计器 -> 身份检查器 -> 将类设置为 ExUILabel
然后转到设计器中的属性检查器并设置字体名称。
我想出了更快的修复方法(我假设您总是使用一种自定义字体)。
为 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
只需在故事板中使用您的自定义字体。 当错误解释器将使用系统字体而不是您自己的字体时,此类别会将其切换为您的自定义字体。
我遇到了同样的问题,找到了一个不太清楚但很好的解决方案!
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) } } }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.