[英]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.