web-dev-qa-db-ja.com

Xcode 6サイズクラスのカスタムフォントサイズ設定がカスタムフォントで正しく機能しない

Xcode 6には、UILabel、UITextField、およびUIButtonのフォントとフォントサイズを、現在のデバイス構成のサイズクラスに基づいてストーリーボードで自動的に設定できる新しい機能があります。たとえば、UILabelを設定して、「任意の幅、コンパクトな高さ」(横長のiPhoneなど)構成でフォントサイズ12を、「通常の幅、通常の高さ」構成(iPadなど)でサイズ18を使用できます。詳細についてはこちらをご覧ください。

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

これは、デバイス構成に基づいてUI機能に異なるフォントをプログラムで設定する必要がなくなるため、理論的には非常に優れた機能です。現在、デバイスの種類に基づいてフォントを設定する条件付きコードがいくつかありますが、明らかに、アプリ全体のどこでもフォントをプログラムで設定する必要があります。そのため、最初はこの機能に本当に興奮していましたが、実際の使用には深刻な問題(おそらくバグ)があることがわかりました。 SDK 8に対してビルドし、iOS 8の最小展開ターゲットを設定しているため、これはiOSの古いバージョンとの互換性とは関係ありません。

問題はこれです:サイズクラスごとに異なるフォントサイズを設定し、iOSが提供する「システム」フォントを使用すると、すべてが期待どおりに機能し、サイズクラスに基づいてフォントサイズが変化します。アプリケーションで提供されるカスタムフォントを使用する場合(はい、プログラムで動作するため、アプリケーションバンドルで正しく設定します)、カスタムフォントをXCode 6ストーリーボードのラベルに設定します。これも期待どおりに動作します。しかし、ストーリーボードで、サイズクラスごとに異なるサイズのカスタムフォントを使用しようとすると、突然機能しなくなります。構成の唯一の違いは、選択したフォント(カスタムフォントとシステムフォント)です。代わりに、サイズクラスに関係なく、すべてのフォントがデフォルトのサイズでデフォルトのシステムフォントとしてデバイスおよびシミュレーターに表示されます(ストーリーボードで指定された実際のフォントをシステムフォントに置き換えていることをデバッガーで確認しました) 。そのため、基本的に、サイズクラス機能はカスタムフォントでは壊れているように見えます。また、興味深いことに、カスタムフォントは、実際にView ControllerのXCode 6の[プレビュー]ペインでサイズを適切に表示および調整します。実際のiOSシステムで実行しているときのみ、動作を停止します(正しく)。

複数の異なるカスタムフォントを試しましたが、どのフォントでも動作しないようですが、代わりに「システム」を使用すると常に動作します。

とにかく、Xcode 6でこの問題を見た人はいますか?これがiOS 8のバグであるか、Xcodeであるか、または私が間違っているのかについてのアイデアはありますか?私が見つけた唯一の回避策は、私が言ったように、iOSの約3つのバージョンのようにプログラムでフォントを設定し続けることです。しかし、カスタムフォントで動作させることができれば、この機能を使用できるようになりたいです。システムフォントを使用することは、デザインでは受け入れられません。


追加情報:Xcode 8.0では、バグが修正されています。

103
mnemia

高速修正:

1)サイズクラスのフォントをシステムとして設定する

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

}

ちなみに、それは象徴的なフォントにとって非常に便利なテクニックです

40
razor28

すべてを試した後、私は最終的に上記のソリューションの組み合わせに落ち着きました。 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_では、ストーリーボードでフォントサイズを設定できます
  • didSetオブザーバーを使用して、layoutSubviews()(動的なテーブルビューの行の高さの無限ループ)とawakeFromNib()(@cocoaNoobのコメントを参照)の落とし穴を回避します。
  • 最終的に_@IBDesignable_でこれを使用することを期待して、デバイスイディオムではなくサイズクラスを使用します
  • 悲しいことに、_@IBDesignable_はtraitCollectionでは動作しません。これは他の スタック記事
  • 特性コレクションswitchステートメントは、これごとにselfではなくUIScreen.mainScreen()で実行されます stack article
17
Robert Chen

回避策 for UILabel:すべてのサイズクラスで同じフォントサイズを維持しますが、代わりに各サイズクラスでラベルの高さを適宜変更します。ラベルの自動圧縮を有効にする必要があります。私の場合はうまくいきました。

9
Phil

この(および他のXcode-サイズクラスに関連する)バグにより、最近、物事をハッキングする巨大なストーリーボードファイルを調べなければならなかったため、深刻な悲しみが生じました。

このポジションにいる他の人のために、痛みを和らげるために@ razor28の答えの上に何かを追加したいです。

カスタムサブクラスのヘッダーファイルで、ランタイム属性にIBInspectableを使用します。これにより、フォント設定のデフォルトの位置のすぐ上にある「属性インスペクター」からこれらの属性にアクセスできるようになります。

使用例:

@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で適切な修正が行われることを願っています。

8
joakim

@ razor28のソリューションと同様のソリューションですが、もう少し普遍的だと思います。また、古いiOSバージョンでも正常に動作します

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

3
Vitaly

バグは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のカスタムクラスを設定してから、フォントサイズクラスを設定しますシステムフォントを使用して

enter image description here

3
Foti Dim

インターフェイスビルダーからさまざまなサイズのクラスのフォントを設定する機能を使用できないという問題がまだあります。

以下のように、必要なデバイスに基づいてフォントを設定するだけです。

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

これはすべてのデバイスで完全に機能します。

0
Nirmit Dagly

まだ署名された正しい答えはありません。このコードは私にとってはうまく機能します。最初に、インターフェイスビルダーでサイズクラスのフォントサイズを無効にする必要があります。 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
Max Smirnov

上記の後半の回答のいくつかの組み合わせは役に立ちました。 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
benjam

これらのどれも私にとってはうまくいきませんでしたが、これはうまくいきました。また、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
Jules