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


104

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

developer.apple.com/size_class

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

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

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

とにかく、Xcode 6でこの問題を見た人はいますか?

これがiOS 8、Xcode、または何かのバグかどうかに関するアイデア

私は間違っていますか?

言ったように、私が見つけた唯一の回避策は、私がiOSの約3つのバージョンで行ったように、プログラムでフォントを設定し続けることです。

しかし、カスタムフォントで機能させることができれば、この機能を使用できるようになりたいです。システムフォントの使用は、私たちのデザインには受け入れられません。


追加情報: Xcode 8.0以降、バグが修正されました。


3
これは、xCode 6.1(6A1052d)アプリストアのリリースでも同じです。
jodm 2014年

3
解決策ではありませんが、カテゴリを使用して問題を回避することができました。私のカテゴリUILabel + Font.h(ボタンにも1つあります)には、次のコードが含まれています。-(void)awakeFromNib {float size = [self.font pointSize]; self.font = [UIFont fontWithName:@ "YourCustomFont" size:size]; したがって、これにより、システムフォントでサイズクラスを使用してポイント値をさまざまなサイズクラスに設定でき、カテゴリによって正しいフォントが設定されることが保証されます。たぶん、あなたはAppleがアップデートをリリースするまでそれを試してみることができますか?
ダニエル・レティエフ・フーリー2015年

2
Xcode 6.3.1ではまだ解決されていません。私はこれに腹を立てています。
フューリー

7
Xcode 7 finalではまだ機能しません。Appleがそれを修正しない理由を理解していない。
ernesto 2015

5
Xcode 7.2 iOS 9.2ではまだ機能しません
Mojtaba

回答:


41

迅速な修正:

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

ラベル属性インスペクター

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

}

ちなみに、アイコンフォントにはとても便利なテクニックです


これは、アプリ全体で使用されるフォントが同じである場合は適切な回避策ですが、異なる場所で異なるフォントを使用する必要がある場合は、サブクラスなどが異なるため、少し不便です。私の場合、私はすでにプログラマティックフォントを設定しました。そのための方法はたくさんあります。しかし、私の質問の要点は、プログラムでこれを行う方法を尋ねることではありません。ストーリーボードを使用してこれが正しく機能しない理由を尋ねることです(これはAppleのバグです)。
mnemia

@mnemia同意する。私の目的は、そのバグを処理する方法を示すことです。
razor28 2015年

1
よく働く。ただし、UILabelをサブクラス化する必要はありません。ラベルを保持するビューでこのメソッドをオーバーライドするだけself.label.font = ...で、さまざまな場所でさまざまなフォントを使用できます。
KPM 2015

または、@ IBInspectableを設定して、フォント名を保存し、同じカスタムラベルクラスを再利用して、ストーリーボードで直接異なるフォントをリクエストすることもできます。
Craig Grummitt、2015年

UITextFieldに同様のソリューションはありますか?
Chris Byatt、2015年

17

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

ベストアンサーですが、残念ながら投票結果は下です。ありがとう
Rohit Pradhan

9

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


1
各サイズクラスでラベルの幅を変更することで、同じことを行うことができました。良いヒントです!
dmzza

1
UILabelの固定高さを小さく設定してフォントを縮小できませんでした。正確にどのように機能させましたか?adjustsFontSizeToFitWidth幅に対してのみ機能するようです(ラベルのテキストが動的であるため使用できません)。
ernesto

幅に合わせて調整すると同じ問題があります
Jules

1
結局、スーパービューの高さに比例してラベルの高さ制限を設定することになりました。長い間、あなたが0にIBにおけるラベルの「行」のパラメータを設定したとして罰金を動作すること
ドリアンロイ

8

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

この立場にいる他の誰にとっても、痛みを和らげるために@ razor28の答えの上に何かを追加したいと思います。

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

使用例:

@interface MyCustomLabel : UILabel

    @property (nonatomic) IBInspectable NSString *fontType;
    @property (nonatomic) IBInspectable CGFloat iphoneFontSize;
    @property (nonatomic) IBInspectable CGFloat ipadFontSize;

@end

これは非常に便利にこの出力を生成します:

ここに画像の説明を入力してください

追加の利点は、各ラベルにランタイム属性を手動で追加する必要がないことです。これは、XCodeの意図した動作に最も近いものです。この夏、iOS 9で適切な修正が行われることを願っています。


私はあなたの指示に従って追加しましたが、xibで「Attributes Inspector」へのアクセスを視覚的に見つけることができないので、どのようにそれを達成するのですか?
Darshan Kunjadiya 2016年

3

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

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


そして、確かに、Interface BuilderでプロパティoverrideFontNameを設定することで、不要なコードの記述を回避できます
Vitaly

これは私のために仕事をしませんでした、私は上記の方法の中にインストールされているすべてのフォントを列挙し、私のフォントが表示され、変数に割り当てられますが、シミュレータ上のラベルのフォントショーを変化させなかったと私はデバイスを想定した
ジュール

3

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

ここに画像の説明を入力してください


@ Maarten1909回避策または簡単なXCodeの方法を参照していますか?最初のバージョンを指定できる場合は、バージョンを指定して再現してみますか?
Foti Dim 2015

いつも間違ったフォントファミリ名を使用しているようです。このような場合、フォントは14.0パイントサイズのシステムフォントにリセットされることがわかります。私の悪い。しかし、それは他の人に役立つかもしれません!
Berendschot 2015

0

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

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

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

これらはどれもうまくいきませんでしたが、うまくいきました。また、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)")
            }
        }
    }
}

-1

私は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)
        }
    }
  1. Goto Designer-> Identity Inspector-> Set the class to ExUILabel

  2. 次に、デザイナーの属性インスペクターに移動し、フォント名を設定します。


-1

私はさらに速い修正を思いつきました(私はあなたがいつもあなたの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

ストーリーボードでカスタムフォントを使用するだけです。バギーインタープリターがシステムフォントを使用する場合、独自のこのカテゴリはカスタムフォントに切り替えます。


-1:このようなカテゴリのメソッドをオーバーライドすることはお勧めできません。理由:stackoverflow.com/questions/5272451/… 代わりに、スウィズル(ハッキーですが)またはサブクラスにする必要があります。
JRG-Developer 2016

-6

私は同じ問題を抱えていて、明確ではないものの素晴らしい解決策を見つけました!

  1. 最初に、ストーリーボードで必要なフォントサイズをシステムフォント名で設定します。
  2. 次に、このラベルに100から110までのタグを割り当てます(1つのビューコントローラでは、常に10で十分です)。
  3. 次に、このコードをVCのソースファイルに配置し、フォント名を変更することを忘れないでください。迅速なコード。
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)
        }
    }
}

1
タグを使用しないでください。IBOutletsを使用します。タグが悪いです。WWDC 2015セッション231を参照してください。これの代わりに、クラスでプロパティを宣言すると、後で必要になるビューへの実際の接続が確立されます。」
KPM 2015

この解決策は完璧ではないのですが、うまくいきます。
serg_ov

-8
  • アプリケーションが提供するフォントをアプリの.plistに追加する
  • .ttfファイルをアイテム0に追加します
  • 使用する[UIFont fontWithName: "example.ttf" size:10]

これはこの問題に対する答えではありません。プログラムでカスタムフォントを使用できることは明らかですが、私の質問は、サイズクラスに応じてカスタムフォントが自動的に変更されないというiOS 8のバグです。
mnemia
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.