UILabelのフォントサイズを動的に変更する


188

私は現在UILabel

factLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 280, 100)];
factLabel.text = @"some text some text some text some text";
factLabel.backgroundColor = [UIColor clearColor];
factLabel.lineBreakMode = UILineBreakModeWordWrap;
factLabel.numberOfLines = 10;
[self.view addSubview:factLabel];

私のiOSアプリケーションの存続期間を通して、factLabelさまざまな値の束を取得します。複数の文があるものもあれば、5語または6語しかないものもあります。

UILabelフォントサイズを変更して、テキストが常に定義した範囲に収まるようにを設定するにはどうすればよいですか?


2
2016年については、「自動圧縮を使用する」アプローチを使用することが唯一の良い解決策であると私は本当に信じています。UILabelボックスを実際のサイズにして、フォントをUILabelに合わせ、自動圧縮を選択し、巨大なフォントサイズ(300)を設定します。最小/最大のシミュレータでテストしてください。(つまり、現在4s / PadProです。)完全な説明:stackoverflow.com/a/35154493/294884 これが現在唯一の実際のソリューションです。
Fattie

回答:


370

単線:

factLabel.numberOfLines = 1;
factLabel.minimumFontSize = 8;
factLabel.adjustsFontSizeToFitWidth = YES;

上記のコードは、テキストのフォントサイズを(たとえば)8テキストをラベル内に収まるように調整します。 numberOfLines = 1必須です。

複数行:

numberOfLines > 1最終テキストの大きさを把握するための方法があるのNSStringのsizeWithFont:... UIKitの添加方法、例えば:

CGSize lLabelSize = [yourText sizeWithFont:factLabel.font
                                  forWidth:factLabel.frame.size.width
                             lineBreakMode:factLabel.lineBreakMode];

その後、lLabelSizeたとえば、結果のを使用してラベルのサイズを変更できます(ラベルの高さのみを変更するとします):

factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, factLabel.frame.size.width, lLabelSize.height);

iOS6

単線:

iOS6以降、minimumFontSize非推奨になりました。この線

factLabel.minimumFontSize = 8.;

次のように変更できます。

factLabel.minimumScaleFactor = 8./factLabel.font.pointSize;

iOS7

複数行:

iOS7以降、sizeWithFont非推奨となりました。複数行のケースは次のように削減されます。

factLabel.numberOfLines = 0;
factLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(factLabel.frame.size.width, CGFLOAT_MAX);
CGSize expectSize = [factLabel sizeThatFits:maximumLabelSize];
factLabel.frame = CGRectMake(factLabel.frame.origin.x, factLabel.frame.origin.y, expectSize.width, expectSize.height);

iOS 13(Swift 5):

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5

しかし、これはテキストをすべて1行に配置します。factLabel.numberOfLinesを変更しても、フォントサイズは動的に変更されません。
CodeGuy、2011

@ reising1:あなたは正しい。これは、サイズ変更作業を行うためのフレームワークを作成する方法です。
Martin Babacaev、2011

それで私の質問への答えは、提供されたフレームワークを使用してそれを行う方法はないということですか?
CodeGuy、2011

1
@ reising1:この場合、NSString UIKit追加のメソッドを使用することもできます。sizeWithFont:constrainedToSize:lineBreakMode:ただし、この方法は少し難しい
Martin Babacaev

6
iOS6以降は非推奨です。交換してくださいmyLabel.minimumScaleFactor:10.0/[UIFont labelFontSize];
Norbert

72

minimumFontSizeiOS 6では廃止されましたminimumScaleFactor。を使用できます。

yourLabel.adjustsFontSizeToFitWidth=YES;
yourLabel.minimumScaleFactor=0.5;

これにより、ラベルとテキストの幅に応じてフォントサイズが調整されます。


0.7でも小さすぎるように見えるので、私は通常0.8を使用します。もちろん、一部のテキストは最小のスケールファクター0.8に適合しない場合があります。見栄えを良くしたり、判読できない場所を決定したりすることです。OTOH私のアプリは回転させることができ、とても役に立ちます。
gnasher729

adjustsFontSizeToFitWidthコンテナに収まらない場合にのみテキストを縮小します
ユーザー25

24

@Eyal Ben Dovの回答に基づいて、カテゴリを作成して、他のアプリ内で柔軟に使用できるようにすることができます。

Obs .: iOS 7と互換性を持つように彼のコードを更新しました

-ヘッダーファイル

#import <UIKit/UIKit.h>

@interface UILabel (DynamicFontSize)

-(void) adjustFontSizeToFillItsContents;

@end

-実装ファイル

#import "UILabel+DynamicFontSize.h"

@implementation UILabel (DynamicFontSize)

#define CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE 35
#define CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE 3

-(void) adjustFontSizeToFillItsContents
{
    NSString* text = self.text;

    for (int i = CATEGORY_DYNAMIC_FONT_SIZE_MAXIMUM_VALUE; i>CATEGORY_DYNAMIC_FONT_SIZE_MINIMUM_VALUE; i--) {

        UIFont *font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
        NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName: font}];

        CGRect rectSize = [attributedText boundingRectWithSize:CGSizeMake(self.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil];

        if (rectSize.size.height <= self.frame.size.height) {
            self.font = [UIFont fontWithName:self.font.fontName size:(CGFloat)i];
            break;
        }
    }

}

@end

-使用法

#import "UILabel+DynamicFontSize.h"

[myUILabel adjustFontSizeToFillItsContents];

乾杯


うまくいきません。現在、UILabelのコンテンツが途切れています。
エイドリアン

1
うまくいかない場合は、ラベルのフレームがまだ設定されていない可能性があります。これを呼び出す前にフレームを設定してみてください(またはAutoLayoutを使用している場合はsetNeedsLayout/を呼び出しlayoutIfNeededます)。
bmueller 2014

次のクラッシュが発生します "'NSInvalidArgumentException"、理由:' NSConcreteAttributedString initWithString :: nil value '"
Mohamed Saleh

つまり、NSStringをnilにすることはできません。UILabelのコンテンツを満たすようにフォントサイズを調整する場合は、少なくともテキストを提供する必要があると思います。
Paulo Miguel Almeida

これには欠点があります。文字間で改行されるため、単語が別の行に分割されていることがわかります。これを回避する方法はありますか?
Özgür

23

単一行 -2つの方法があり、簡単に変更できます。

1-実用的(Swift 3)

次のコードを追加するだけです

    yourLabel.numberOfLines = 1;
    yourLabel.minimumScaleFactor = 0.7;
    yourLabel.adjustsFontSizeToFitWidth = true;

2-UILabel属性インスペクターの使用

i- Select your label- Set number of lines 1.
ii- Autoshrink-  Select Minimum Font Scale from drop down
iii- Set Minimum Font Scale value as you wish , I have set 0.7 as in below image. (default is 0.5)

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


22

それは2015年です。最新バージョンのiOSおよびXCodeでSwiftを使用して複数行で動作するようにする方法を説明するブログ記事を見つけに行かなければなりませんでした。

  1. 「自動縮小」を「最小フォントサイズ」に設定します。
  2. フォントを最大のフォントサイズに設定します(20を選択しました)
  3. 「改行」を「ワードラップ」から「切り捨て」に変更します。

出典:http : //beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/


これは本当に命の恩人です!!
bhakti123 2016

2
とてもクールです..切り捨てられたテールポイントが最も重要です..ワードラップオートレイアウトの場合のCozは、フォントサイズを小さくする衝動を感じません。次に、フォントのサイズを変更します。
GKK 2016

12

Swiftバージョン:

textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5

ありがとう..ここでもシーケンスのように見える
Pramod

7

UILabelのSwift拡張機能を次に示します。バイナリ検索アルゴリズムを実行して、ラベルの境界の幅と高さに基づいてフォントのサイズを変更します。iOS 9およびautolayoutで動作することがテストされています。

使用法:<label>フォントのサイズ変更が必要な事前定義のUILabelはどこにありますか

<label>.fitFontForSize()

デフォルトでは、この関数は5ptと300ptのフォントサイズの範囲内を検索し、テキストを境界内に「完全に」(1.0pt以内の精度で)収まるように設定します。あなたはパラメータを定義することができているので、例えば、間検索を1ptラベルの現在のフォントサイズを正確内0.1pts次のように:

<label>.fitFontForSize(1.0, maxFontSize: <label>.font.pointSize, accuracy:0.1)

次のコードをコピーしてファイルに貼り付けます

extension UILabel {

    func fitFontForSize(var minFontSize : CGFloat = 5.0, var maxFontSize : CGFloat = 300.0, accuracy : CGFloat = 1.0) {
        assert(maxFontSize > minFontSize)
        layoutIfNeeded() // Can be removed at your own discretion
        let constrainedSize = bounds.size
        while maxFontSize - minFontSize > accuracy {
            let midFontSize : CGFloat = ((minFontSize + maxFontSize) / 2)
            font = font.fontWithSize(midFontSize)
            sizeToFit()
            let checkSize : CGSize = bounds.size
            if  checkSize.height < constrainedSize.height && checkSize.width < constrainedSize.width {
                minFontSize = midFontSize
            } else {
                maxFontSize = midFontSize
            }
        }
        font = font.fontWithSize(minFontSize)
        sizeToFit()
        layoutIfNeeded() // Can be removed at your own discretion
    }

}

注:layoutIfNeeded()呼び出しはそれぞれ独自の裁量で削除できます


ああ-しかし、自動レイアウトでは実際には機能しません。その場合、「sizeToFit」は何もしません。
Fattie

4

少し洗練されていませんが、これは機能するはずです。たとえば、最大ラベルサイズが28のuilabelを120x120に制限するとします。

magicLabel.numberOfLines = 0;
magicLabel.lineBreakMode = NSLineBreakByWordWrapping;
...
magicLabel.text = text;
    for (int i = 28; i>3; i--) {
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:(CGFloat)i] constrainedToSize:CGSizeMake(120.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
        if (size.height < 120) {
            magicLabel.font = [UIFont systemFontOfSize:(CGFloat)i];
            break;
        }
    }

これはかなり非効率のようです。UILabelを動的に高さを上げて、提供されている使用可能なスペースに合わせる必要があります。これをテーブルビューセルのタイトルフォント計算のようなものに実行すると、大きな遅れの問題が発生します。アプローチはうまくいくかもしれませんが、絶対にお勧めできません。
Zorayr、2015

実際に質問に答える唯一の人物であることへの賛成投票。
Jai

2

sizeToFitメッセージをUITextViewに送信するだけです。テキストにぴったり合うように高さが調整されます。それ自体の幅や原点は変更されません。

[textViewA1 sizeToFit];

テキストに合わせたサイズがコンテナのスペースに対して大きすぎる場合はどうなりますか?たとえば、テキストビューに合わせるために100ポイント利用できるとしsizeToFitます。呼び出した後、textViewA1200ポイントになり、最終的にトリミングされます。
Zorayr、2015

0

Swift 2.0バージョン:

private func adapteSizeLabel(label: UILabel, sizeMax: CGFloat) {
     label.numberOfLines = 0
     label.lineBreakMode = NSLineBreakMode.ByWordWrapping
     let maximumLabelSize = CGSizeMake(label.frame.size.width, sizeMax);
     let expectSize = label.sizeThatFits(maximumLabelSize)
     label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, expectSize.width, expectSize.height)
}

0

このソリューションは複数行で機能します。

いくつかの記事に従って、テキストを自動的に拡大縮小して行数を調整し、指定されたラベルサイズに最適になる関数を必要とした後、私は自分で関数を作成しました。(つまり、短い文字列は1行にうまく収まり、ラベルフレームを大量に使用しますが、長い文字列は自動的に2行または3行に分割され、それに応じてサイズを調整します)

自由に再利用して、必要に応じて調整してください。viewDidLayoutSubviews終了後に呼び出して、最初のラベルフレームが設定されていることを確認してください。

+ (void)setFontForLabel:(UILabel *)label withMaximumFontSize:(float)maxFontSize andMaximumLines:(int)maxLines {
    int numLines = 1;
    float fontSize = maxFontSize;
    CGSize textSize; // The size of the text
    CGSize frameSize; // The size of the frame of the label
    CGSize unrestrictedFrameSize; // The size the text would be if it were not restricted by the label height
    CGRect originalLabelFrame = label.frame;

    frameSize = label.frame.size;
    textSize = [label.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize: fontSize]}];

    // Work out the number of lines that will need to fit the text in snug
    while (((textSize.width / numLines) / (textSize.height * numLines) > frameSize.width / frameSize.height) && (numLines < maxLines)) {
        numLines++;
    }

    label.numberOfLines = numLines;

    // Get the current text size
    label.font = [UIFont systemFontOfSize:fontSize];
    textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
                                        options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                     attributes:@{NSFontAttributeName : label.font}
                                        context:nil].size;

    // Adjust the frame size so that it can fit text on more lines
    // so that we do not end up with truncated text
    label.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y, label.frame.size.width, label.frame.size.width);

    // Get the size of the text as it would fit into the extended label size
    unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;

    // Keep reducing the font size until it fits
    while (textSize.width > unrestrictedFrameSize.width || textSize.height > frameSize.height) {
        fontSize--;
        label.font = [UIFont systemFontOfSize:fontSize];
        textSize = [label.text boundingRectWithSize:CGSizeMake(frameSize.width, CGFLOAT_MAX)
                                            options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                         attributes:@{NSFontAttributeName : label.font}
                                            context:nil].size;
        unrestrictedFrameSize = [label textRectForBounds:CGRectMake(0, 0, label.bounds.size.width, CGFLOAT_MAX) limitedToNumberOfLines:numLines].size;
    }

    // Set the label frame size back to original
    label.frame = originalLabelFrame;
}

0

以下は、アニメーションフォントサイズの変更を実装するUILabelサブクラスの塗りつぶしコードです。

@interface SNTextLayer : CATextLayer

@end

@implementation SNTextLayer

- (void)drawInContext:(CGContextRef)ctx {
    // We override this to make text appear at the same vertical positon as in UILabel
    // (otherwise it's shifted tdown)
    CGFloat height = self.bounds.size.height;
    float fontSize = self.fontSize;
    // May need to adjust this somewhat if it's not aligned perfectly in your implementation
    float yDiff = (height-fontSize)/2 - fontSize/10;

    CGContextSaveGState(ctx);
    CGContextTranslateCTM(ctx, 0.0, yDiff);
    [super drawInContext:ctx];
     CGContextRestoreGState(ctx);
}

@end

@interface SNAnimatableLabel ()

@property CATextLayer* textLayer;

@end

@interface SNAnimatableLabel : UILabel

- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration;

@end



@implementation SNAnimatableLabel


- (void)awakeFromNib {
    [super awakeFromNib];
    _textLayer = [SNTextLayer new];
    _textLayer.backgroundColor = self.backgroundColor.CGColor;
    _textLayer.foregroundColor = self.textColor.CGColor;
    _textLayer.font = CGFontCreateWithFontName((CFStringRef)self.font.fontName);
    _textLayer.frame = self.bounds;
    _textLayer.string = self.text;
    _textLayer.fontSize = self.font.pointSize;
    _textLayer.contentsScale = [UIScreen mainScreen].scale;
    [_textLayer setPosition: CGPointMake(CGRectGetMidX(_textLayer.frame), CGRectGetMidY(_textLayer.frame))];
    [_textLayer setAnchorPoint: CGPointMake(0.5, 0.5)];
    [_textLayer setAlignmentMode: kCAAlignmentCenter];
    self.textColor = self.backgroundColor;
    // Blend text with background, so that it doens't interfere with textlayer text
    [self.layer addSublayer:_textLayer];
    self.layer.masksToBounds = NO;
}

- (void)setText:(NSString *)text {
    _textLayer.string = text;
    super.text = text;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    // Need to enlarge the frame, otherwise the text may get clipped for bigger font sizes
    _textLayer.frame = CGRectInset(self.bounds, -5, -5);
}

- (void)animateFontToSize:(CGFloat)fontSize withDuration:(double)duration {
    [CATransaction begin];
    [CATransaction setAnimationDuration:duration];
    _textLayer.fontSize = fontSize;
    [CATransaction commit];
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.