Custom Font Sizing in Xcode 6 Size Classes not working properly with Custom Fonts
Solution 1:
Fast fix:
1) Set fonts as System for size classes
2) Subclass UILabel and override "layoutSubviews" method like:
- (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
Solution 2:
After trying everything, I eventually settled on a combination of the above solutions. Using 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 - It uses a
didSet
observer, to avoid the pitfalls fromlayoutSubviews()
(infinite loop for dynamic table view row heights) andawakeFromNib()
(see @cocoaNoob's comment) - It uses size classes rather than the device idiom, in hopes of eventually using this with
@IBDesignable
- Sadly,
@IBDesignable
doesn't work withtraitCollection
according to this other stack article - The trait collection switch statement is performed on
UIScreen.mainScreen()
rather thanself
per this stack article
Solution 3:
Workaround for UILabel
: keep the same font size on all Size Classes, but instead change your label height accordingly in each Size Class. Your label must have autoshrink enabled. It worked nicely in my case.
Solution 4:
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.
For anyone else in this position, I'd like to add something on top of @razor28's answer to ease the pain.
In the header file of your custom subclass, use IBInspectable
for your runtime attributes. 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. Hopefully a proper fix is on its way with iOS 9 this summer.