简体   繁体   English

动态改变 UILabel 的字体大小

[英]Dynamically changing font size of UILabel

I currently have a UILabel :我目前有一个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];

Throughout the life of my iOS application, factLabel gets a bunch of different values.在我的 iOS 应用程序的整个生命周期中, factLabel获得了一堆不同的值。 Some with multiple sentences, others with just 5 or 6 words.有些有多个句子,有些只有 5 或 6 个词。

How can I set up the UILabel so that the font size changes so that the text always fits in the bounds I defined?如何设置UILabel以便更改字体大小,以便文本始终适合我定义的边界?

Single line:单行:

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

The above code will adjust your text's font size down to (for example) 8 trying to fit your text within the label.上面的代码会将您的文本的字体大小调整为(例如) 8试图让您的文本适合标签。 numberOfLines = 1 is mandatory. numberOfLines = 1是强制性的。

Multiple lines:多行:

For numberOfLines > 1 there is a method to figure out the size of final text through NSString's sizeWithFont:... UIKit addition methods, for example:对于numberOfLines > 1有一种方法可以通过NSString 的 sizeWithFont:... UIKit 添加方法来计算最终文本的大小,例如:

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

After that you can just resize your label using resulting lLabelSize , for example (assuming that you will change only label's height):之后,您可以使用生成的lLabelSize调整标签大小,例如(假设您将仅更改标签的高度):

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

iOS6 iOS6

Single line:单行:

Starting with iOS6, minimumFontSize has been deprecated.从 iOS6 开始, minimumFontSize已被弃用。 The line线

factLabel.minimumFontSize = 8.;

can be changed to:可以改为:

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

iOS7 iOS7

Multiple lines:多行:

Starting with iOS7, sizeWithFont becomes deprecated.从 iOS7 开始,不推荐使用sizeWithFont Multiline case is reduced to:多行情况简化为:

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): iOS 13 (Swift 5):

label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.5

minimumFontSize has been deprecated with iOS 6. You can use minimumScaleFactor . minimumFontSize已在 iOS 6 中弃用。您可以使用minimumScaleFactor

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

This will take care of your font size according width of label and text.这将根据标签和文本的宽度处理您的字体大小。

Single line - There are two ways, you can simply change.单行- 有两种方式,您可以简单地更改。

1- Pragmatically (Swift 3) 1- 务实(Swift 3)

Just add the following code只需添加以下代码

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

2 - Using UILabel Attributes inspector 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)

在此处输入图片说明

Based on @Eyal Ben Dov's answer you may want to create a category to make it flexible to use within another apps of yours.根据@Eyal Ben Dov 的回答,您可能希望创建一个类别,使其灵活地在您的其他应用程序中使用。

Obs.: I've updated his code to make compatible with iOS 7观察:我已经更新了他的代码以与 iOS 7 兼容

-Header file - 头文件

#import <UIKit/UIKit.h>

@interface UILabel (DynamicFontSize)

-(void) adjustFontSizeToFillItsContents;

@end

-Implementation file -实施文件

#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

-Usage -用法

#import "UILabel+DynamicFontSize.h"

[myUILabel adjustFontSizeToFillItsContents];

Cheers干杯

It's 2015. I had to go to find a blog post that would explain how to do it for the latest version of iOS and XCode with Swift so that it would work with multiple lines.现在是 2015 年。我不得不去找一篇博客文章来解释如何使用 Swift 为最新版本的 iOS 和 XCode 执行此操作,以便它可以处理多行。

  1. set “Autoshrink” to “Minimum font size.”将“自动收缩”设置为“最小字体大小”。
  2. set the font to the largest desirable font size (I chose 20)将字体设置为所需的最大字体大小(我选择了 20)
  3. Change “Line Breaks” from “Word Wrap” to “Truncate Tail.”将“换行符”从“自动换行”更改为“截尾”。

Source: http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/资料来源: http : //beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/

Swift version:迅捷版:

textLabel.adjustsFontSizeToFitWidth = true
textLabel.minimumScaleFactor = 0.5

Here's a Swift extension for UILabel.这是 UILabel 的 Swift 扩展。 It runs a binary search algorithm to resize the font based off the width and height of the label's bounds.它运行二进制搜索算法,根据标签边界的宽度和高度调整字体大小。 Tested to work with iOS 9 and autolayout.经测试可与 iOS 9 和自动布局配合使用。

USAGE: Where <label> is your pre-defined UILabel that needs font resizing用法:其中<label>是需要调整字体大小的预定义 UILabel

<label>.fitFontForSize()

By Default, this function searches in within the range of 5pt and 300pt font sizes and sets the font to fit its text "perfectly" within the bounds (accurate within 1.0pt).默认情况下,此功能在 5pt 和 300pt 字体大小范围内搜索,并将字体设置为“完美”地适合其文本在边界内(精确到 1.0pt)。 You could define the parameters so that it, for example, searches between 1pt and the label's current font size accurately within 0.1pts in the following way:你可以定义参数,使得它,例如,1点,准确地内以下列方式0.1pts标签的当前字体大小之间的搜索:

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

Copy/Paste the following code into your file将以下代码复制/粘贴到您的文件中

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
    }

}

NOTE: Each of the layoutIfNeeded() calls can be removed at your own discretion注意:您可以自行决定删除每个layoutIfNeeded()调用

Its a little bit not sophisticated but this should work, for example lets say you want to cap your uilabel to 120x120, with max font size of 28:它有点不复杂,但这应该可以工作,例如,假设您想将 uilabel 限制为 120x120,最大字体大小为 28:

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

Just send the sizeToFit message to the UITextView.只需将 sizeToFit 消息发送到 UITextView。 It will adjust its own height to just fit its text.它将调整自己的高度以适合其文本。 It will not change its own width or origin.它不会改变自己的宽度或原点。

[textViewA1 sizeToFit];

Swift 2.0 Version:斯威夫特 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)
}

This solution works for multiline:此解决方案适用于多行:

After following several articles, and requiring a function that would automatically scale the text and adjust the line count to best fit within the given label size, I wrote a function myself.在阅读了几篇文章后,需要一个能够自动缩放文本并调整行数以最适合给定标签大小的函数,我自己编写了一个函数。 (ie. a short string would fit nicely on one line and use a large amount of the label frame, whereas a long strong would automatically split onto 2 or 3 lines and adjust the size accordingly) (即,短字符串可以很好地放在一行上并使用大量标签框架,而长字符串会自动分成 2 或 3 行并相应地调整大小)

Feel free to re-use it and tweak as required.随意重用它并根据需要进行调整。 Make sure you call it after viewDidLayoutSubviews has finished so that the initial label frame has been set.确保在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;
}

Here is the fill code of a UILabel subclass that implements animated font size change:这是实现动画字体大小更改的 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];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM