如何设置字体大小以填充UILabel高度?

时间:2012-01-10 23:41:57

标签: iphone objective-c ios xcode

我看过很多改变UILabel大小的例子。

以下是我想做的事情: 更改字体大小,以便文本在新高度内尽可能大。

任何线索?

21 个答案:

答案 0 :(得分:38)

我遇到了同样的问题,多亏了这个帖子和Joel的算法,我可以解决它。 : - )

下面是我在Swift中的代码。我在iOS 8 + Autolayout。

  

<强>问题:

  1. 用户输入费用:
  2. 123 app

    1. 当用户点击“检查”按钮时,会从底部显示一个菜单,将所有内容推送到屏幕顶部(缩小内容,包括标签):
    2. 123 app

        

      修复后:

      123 app

      这正是设计师的想法...... :)。

      xScope app :)

      我将UILabel子类化并覆盖layoutSubviews。然后每次UILabel更改其大小时,都会重新计算字体大小:

      //
      //  LabelWithAdaptiveTextHeight.swift
      //  123
      //
      //  Created by https://github.com/backslash-f on 12/19/14.
      //
      
      /*
       Designed with single-line UILabels in mind, this subclass 'resizes' the label's text (it changes the label's font size)
       everytime its size (frame) is changed. This 'fits' the text to the new height, avoiding undesired text cropping.
       Kudos to this Stack Overflow thread: bit.ly/setFontSizeToFillUILabelHeight
      */
      
      import Foundation
      import UIKit
      
      class LabelWithAdaptiveTextHeight: UILabel {
      
          override func layoutSubviews() {
              super.layoutSubviews()
              font = fontToFitHeight()
          }
      
          // Returns an UIFont that fits the new label's height.
          private func fontToFitHeight() -> UIFont {
      
              var minFontSize: CGFloat = DISPLAY_FONT_MINIMUM // CGFloat 18
              var maxFontSize: CGFloat = DISPLAY_FONT_BIG     // CGFloat 67
              var fontSizeAverage: CGFloat = 0
              var textAndLabelHeightDiff: CGFloat = 0
      
              while (minFontSize <= maxFontSize) {
      
                  fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2
      
                  // Abort if text happens to be nil
                  guard text?.characters.count > 0 else {
                    break
                  }
      
                  if let labelText: NSString = text {
                      let labelHeight = frame.size.height
      
                      let testStringHeight = labelText.sizeWithAttributes(
                          [NSFontAttributeName: font.fontWithSize(fontSizeAverage)]
                      ).height
      
                      textAndLabelHeightDiff = labelHeight - testStringHeight
      
                      if (fontSizeAverage == minFontSize || fontSizeAverage == maxFontSize) {
                          if (textAndLabelHeightDiff < 0) {
                              return font.fontWithSize(fontSizeAverage - 1)
                          }
                          return font.fontWithSize(fontSizeAverage)
                      }
      
                      if (textAndLabelHeightDiff < 0) {
                          maxFontSize = fontSizeAverage - 1
      
                      } else if (textAndLabelHeightDiff > 0) {
                          minFontSize = fontSizeAverage + 1
      
                      } else {
                          return font.fontWithSize(fontSizeAverage)
                      }
                  }
              }
              return font.fontWithSize(fontSizeAverage)
          }
      }
      

答案 1 :(得分:30)

以下是我的表现,因为DGund的回答并不适合我,它适合宽度,但我希望它适合高度。

+ (UIFont *)findAdaptiveFontWithName:(NSString *)fontName forUILabelSize:(CGSize)labelSize withMinimumSize:(NSInteger)minSize
{
    UIFont *tempFont = nil;
    NSString *testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    NSInteger tempMin = minSize;
    NSInteger tempMax = 256;
    NSInteger mid = 0;
    NSInteger difference = 0;

    while (tempMin <= tempMax) {
        mid = tempMin + (tempMax - tempMin) / 2;
        tempFont = [UIFont fontWithName:fontName size:mid];
        difference = labelSize.height - [testString sizeWithFont:tempFont].height;

        if (mid == tempMin || mid == tempMax) {
            if (difference < 0) {
                return [UIFont fontWithName:fontName size:(mid - 1)];
            }

            return [UIFont fontWithName:fontName size:mid];
        }

        if (difference < 0) {
            tempMax = mid - 1;
        } else if (difference > 0) {
            tempMin = mid + 1;
        } else {
            return [UIFont fontWithName:fontName size:mid];
        }
    }

    return [UIFont fontWithName:fontName size:mid];
}

这将采用字体名称,大小(理论上它不必是UILabel,但我总是将它与UILabel一起使用)和最小尺寸(你也可以使用最大尺寸,只需用max size参数替换256)。这将基本上测试最小和最大字体大小之间的每个字体大小,并返回目标高度处或之下的字体大小。

用法是不言自明的,但看起来像这样:

self.myLabel.font = [self findAdaptiveFontWithName:@"HelveticaNeue-UltraLight" forUILabelSize:self.myLabel.frame.size withMinimumSize:30];

你也可以在UIFont上做这个类方法类别(这就是我所做的)。

编辑:根据建议,我删除了for循环并花了一点时间使用二进制搜索例程使其更有效。我做了几次检查,以确保字体最终适合标签。在初始测试中它似乎有效。

答案 2 :(得分:29)

有一个更简单的解决方案。只需添加以下线条并且神奇地,标签也会调整其字体大小以适应标签的高度:

SWIFT 3:

label.minimumScaleFactor = 0.1    //or whatever suits your need
label.adjustsFontSizeToFitWidth = true    
label.lineBreakMode = .byClipping
label.numberOfLines = 0

答案 3 :(得分:22)

修改:查看Joel Fischer's great answer以编程方式获取正确的尺寸!

您可以将字体设置为自动填充标签的大小,也可以选择不低于最小字体大小。只需将adjustsFontSizeToFitWidth设置为YES.如果您需要更多信息,请查看UILabel Class Reference

虽然布尔值被称为“adjustsFontSizeToFitWidth”,但它实际上意味着标签高度的最大尺寸,它将保留在标签的一行(或者指定的行数)。

答案 4 :(得分:13)

根据我的标签高度调整文本我已经将Joel方法改编为swift

func optimisedfindAdaptiveFontWithName(fontName:String, label:UILabel!, minSize:CGFloat,maxSize:CGFloat) -> UIFont!
{

    var tempFont:UIFont
    var tempHeight:CGFloat
    var tempMax:CGFloat = maxSize
    var tempMin:CGFloat = minSize

    while (ceil(tempMin) != ceil(tempMax)){
        let testedSize = (tempMax + tempMin) / 2


        tempFont = UIFont(name:fontName, size:testedSize)
        let attributedString = NSAttributedString(string: label.text!, attributes: [NSFontAttributeName : tempFont])

        let textFrame = attributedString.boundingRectWithSize(CGSize(width: label.bounds.size.width, height: CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin , context: nil)

        let difference = label.frame.height - textFrame.height
        println("\(tempMin)-\(tempMax) - tested : \(testedSize) --> difference : \(difference)")
        if(difference > 0){
            tempMin = testedSize
        }else{
            tempMax = testedSize
        }
    }


    //returning the size -1 (to have enought space right and left)
    return UIFont(name: fontName, size: tempMin - 1)
}

我用这种方式:

myLabel.font = optimisedfindAdaptiveFontWithName("Helvetica", label: myLabel, minSize: 10, maxSize: 38)
    println("\(myLabel.font)")

答案 5 :(得分:8)

好消息,

完全不需要执行二进制搜索!

您只需使用比率搜索进行迭代(几次)。

        guess = guess * ( desiredHeight / guessHeight )

这是一个完整的IBDesignable解决方案。

注意:与设计师或印刷师合作时,您需要设置字体的跟踪/拉伸。 (这是荒谬的Apple不包含此内容。)StyledLabel 还包括跟踪/拉伸。

StyledLabel.swift

设置跟踪,拉伸和设置点大小以匹配所有设备上的视图帧高度

在故事板中:只需制作UILabel的框架,即文本的高度 - 故事的结尾!

// the call fontToFitHeight FINDS THE POINT SIZE TO "FILL TO HEIGHT".
// Just use autolayout to make the frame THE ACTUAL HEIGHT
// you want the type ON ANY DEVICE

// ADDITIONALLY you can set:
// the tracking (that's the overall amount of space between all letters)
// and streching (actually squeeze or stretch the letters horizontally)

// Note: tracking and stretching IS SHOWN IN STORYBOARD LIVE
// WTT crazyrems http://stackoverflow.com/a/37300130/294884

import UIKit

@IBDesignable
class StyledLabel: UILabel
    {
    @IBInspectable var tracking:CGFloat = 0.8
    // values between about 0.7 to 1.3.  one means normal.

    @IBInspectable var stretching:CGFloat = -0.1
    // values between about -.5 to .5.  zero means normal.

    override func awakeFromNib()
        {
        tweak()
        }

    override func prepareForInterfaceBuilder()
        {
        tweak()
        }

    override func layoutSubviews()
        {
        super.layoutSubviews()
        font = fontToFitHeight()
        }

    private func fontToFitHeight() -> UIFont
        {
/* Apple have failed to include a basic thing needed in handling text: fitting the text to the height. Here's the simplest and fastest way to do that:

        guess = guess * ( desiredHeight / guessHeight )

That's really all there is to it. The rest of the code in this routine is safeguards. Further, the routine iterates a couple of times, which is harmless, to take care of any theoretical bizarre nonlinear sizing issues with strange typefaces. */

        guard text?.characters.count > 0 else { return font }
        let desiredHeight:CGFloat = frame.size.height
        guard desiredHeight>1 else { return font }
        var guess:CGFloat
        var guessHeight:CGFloat

        print("searching for... ", desiredHeight)

        guess = font.pointSize
        if (guess>1&&guess<1000) { guess = 50 }

        guessHeight = sizeIf(guess)

        if (guessHeight==desiredHeight)
            {
            print("fluke, exact match within float math limits, up front")
            return font.fontWithSize(guess)
            }

        var iterations:Int = 4

/* It is incredibly unlikely you would need more than four iterations, "two" would rarely be needed. You could imagine some very strange glyph handling where the relationship is non-linear (or something weird): That is the only theoretical reason you'd ever need more than one or two iterations. Note that when you watch the output of the iterations, you'll sometimes/often see same or identical values for the result: this is correct and expected in a float iteration. */

        while(iterations>0)
            {
            guess = guess * ( desiredHeight / guessHeight )
            guessHeight = sizeIf(guess)

            if (guessHeight==desiredHeight)
                {
                print("unbelievable fluke, exact match within float math limits while iterating")
                return font.fontWithSize(guess)
                }

            iterations -= 1
            }

        print("done. Shame Apple doesn't do this for us!")
        return font.fontWithSize(guess)
        }

    private func sizeIf(pointSizeToTry:CGFloat)->(CGFloat)
        {
        let s:CGFloat = text!.sizeWithAttributes(
            [NSFontAttributeName: font.fontWithSize(pointSizeToTry)] )
            .height

        print("guessing .. ", pointSizeToTry, " .. " , s)
        return s
        }

    private func tweak()
        {
        let ats = NSMutableAttributedString(string: self.text!)
        let rg = NSRange(location: 0, length: self.text!.characters.count)

        ats.addAttribute(
            NSKernAttributeName, value:CGFloat(tracking), range:rg )

        ats.addAttribute(
            NSExpansionAttributeName, value:CGFloat(stretching), range:rg )

        self.attributedText = ats
        }
    }

答案 6 :(得分:6)

在viewWillAppear中调用的一行可以解决问题:

testLabel.font = testLabel.font.fontWithSize(testLabel.frame.height * 2/3)

在故事板中,我将所有标签高度设置为相对于视图的整体高度,这样可以使字体大小与它们一起动态缩放。

请注意,字体大小实际上是标签高度的2/3。如果您使用的字体的尾部低于线条(如y,g,q,p或j),则需要使字体大小为标签高度的比例,以使这些尾部不会被切断关闭。 2/3适用于Helvetica Neue,但根据您使用的字体尝试其他比率。对于没有尾部,数字或全部大写文本的字体,1:1的比例可能就足够了。

答案 7 :(得分:5)

基于@ Conaaando的出色答案,我已将其更新为包含IBDesignable参数的版本,这使得可以在整个界面构建器中对其进行编辑:

enter image description here

代码:

//
//  TIFFitToHeightLabel.swift
//

import Foundation
import UIKit

@IBDesignable class TIFFitToHeightLabel: UILabel {

    @IBInspectable var minFontSize:CGFloat = 12 {
        didSet {
            font = fontToFitHeight()
        }
    }

    @IBInspectable var maxFontSize:CGFloat = 30 {
        didSet {
            font = fontToFitHeight()
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        font = fontToFitHeight()
    }

    // Returns an UIFont that fits the new label's height.
    private func fontToFitHeight() -> UIFont {

        var minFontSize: CGFloat = self.minFontSize
        var maxFontSize: CGFloat = self.maxFontSize
        var fontSizeAverage: CGFloat = 0
        var textAndLabelHeightDiff: CGFloat = 0

        while (minFontSize <= maxFontSize) {
            fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2

            if let labelText: NSString = text {
                let labelHeight = frame.size.height

                let testStringHeight = labelText.sizeWithAttributes(
                    [NSFontAttributeName: font.fontWithSize(fontSizeAverage)]
                    ).height

                textAndLabelHeightDiff = labelHeight - testStringHeight

                if (fontSizeAverage == minFontSize || fontSizeAverage == maxFontSize) {
                    if (textAndLabelHeightDiff < 0) {
                        return font.fontWithSize(fontSizeAverage - 1)
                    }
                    return font.fontWithSize(fontSizeAverage)
                }

                if (textAndLabelHeightDiff < 0) {
                    maxFontSize = fontSizeAverage - 1

                } else if (textAndLabelHeightDiff > 0) {
                    minFontSize = fontSizeAverage + 1

                } else {
                    return font.fontWithSize(fontSizeAverage)
                }
            }
        }
        return font.fontWithSize(fontSizeAverage)
    }
}

答案 8 :(得分:4)

这很大程度上借鉴了乔尔菲舍尔的回答。他的回答只考虑了标签高度 - 我做了一些更改,考虑到标签宽度(给定一个输入字符串),我想要:

typedef enum
{
    kDimensionHeight,
    kDimensionWidth,
} DimensionType;

@implementation UIFont (AdaptiveFont)

+ (UIFont *)_adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelDimension:(CGFloat)labelDimension testString:(NSString *)testString dimension:(DimensionType)dimension
{
    UIFont *tempFont = nil;
    NSInteger tempMin = minSize;
    NSInteger tempMax = 256;
    NSInteger mid = 0;
    NSInteger difference = 0;
    CGFloat testStringDimension = 0.0;

    while (tempMin <= tempMax) {
        @autoreleasepool {
            mid = tempMin + (tempMax - tempMin) / 2;
            tempFont = [UIFont fontWithName:fontName size:mid];

            // determine dimension to test
            if (dimension == kDimensionHeight) {
                testStringDimension = [testString sizeWithFont:tempFont].height;
            } else {
                testStringDimension = [testString sizeWithFont:tempFont].width;
            }
            difference = labelDimension - testStringDimension;

            if (mid == tempMin || mid == tempMax) {
                if (difference < 0) {
                    return [UIFont fontWithName:fontName size:(mid - 1)];
                }
                return [UIFont fontWithName:fontName size:mid];
            }

            if (difference < 0) {
                tempMax = mid - 1;
            } else if (difference > 0) {
                tempMin = mid + 1;
            } else {
                return [UIFont fontWithName:fontName size:mid];
            }
        }
    }
    return [UIFont fontWithName:fontName size:mid];
}

+ (UIFont *)adaptiveFontWithName:(NSString *)fontName minSize:(NSInteger)minSize labelSize:(CGSize)labelSize string:(NSString *)string
{
    UIFont *adaptiveFont = nil;
    NSString *testString = nil;

    // get font, given a max height
    testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    UIFont *fontConstrainingHeight = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.height testString:testString dimension:kDimensionHeight];
    CGSize boundsConstrainingHeight = [string sizeWithFont:fontConstrainingHeight];
    CGSize boundsConstrainingWidth = CGSizeZero;

    // if WIDTH is fine (while constraining HEIGHT), return that font
    if (boundsConstrainingHeight.width <= labelSize.width) {
        adaptiveFont = fontConstrainingHeight;
    } else {
        // get font, given a max width
        // i.e., fontConstrainingWidth
        testString = string;
        adaptiveFont = [UIFont _adaptiveFontWithName:fontName minSize:minSize labelDimension:labelSize.width testString:testString dimension:kDimensionWidth];

        // TEST comparison
        boundsConstrainingWidth = [string sizeWithFont:adaptiveFont];
    }
    return adaptiveFont;
}

答案 9 :(得分:3)

结合@DGund和@Kashif的答案,这是一个简单的IB解决方案:

enter image description here

根据您在自动收缩参数中指定的高度,将文本按高度拟合。

答案 10 :(得分:1)

有一种更简单的方法。只需计算屏幕上每个像素的点数,然后将其乘以标签的高度,即可获得所需的字体大小。
这是自定义方法。选择你想要的任何东西。

TYPE 1.硬编码单行版本:

- (CGFloat) fontSizeFromHeight:(CGFloat)height
{
     return ceilf(height * (10.0 / [@"Tg" sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:10.0]}].height));
}

TYPE 2.清洁版:

- (CGFloat)fontSizeFromHeight:(CGFloat)height
{
    static CGFloat const testFontSize = 12.0;
    static NSString * const testText = @"TestString";
    UIFont *testFont = [UIFont systemFontOfSize:testFontSize];
    CGFloat pixelHeight = [testText sizeWithAttributes:@{NSFontAttributeName:testFont}].height;
    CGFloat pointPerPixel = testFontSize / pixelHeight;
    CGFloat desiredFontSize = ceilf(height * pointPerPixel);
    return desiredFontSize;
}

用法示例:

myLabel.font = [UIFont systemFontOfSize:[self fontSizeFromHeight:myLabel.frame.size.height]];  
myLabel.font = [myLabel.font fontWithSize:[self fontSizeFromHeight:myLabel.frame.size.height]];

答案 11 :(得分:1)

扩展@Joe Blow的答案,这是一个Objective-C类别UILabel+FitToHeight,它允许您轻松导入和切换adjustsFontSizeToFitHeight,就像您已经adjustsFontSizeToFitWidth一样。

<强>的UILabel + FitToHeight.h

#import <UIKit/UIKit.h>

@interface UILabel (FitToHeight)

@property (nonatomic, assign) BOOL adjustsFontSizeToFitHeight;

@end

<强>的UILabel + FitToHeight.m

#import "UILabel+FitToHeight.h"

#import <objc/runtime.h>

@implementation UILabel (FitToHeight)

-(BOOL)adjustsFontSizeToFitHeight {
    NSNumber *number = objc_getAssociatedObject(self, @selector(adjustsFontSizeToFitHeight));
    return [number boolValue];
}

-(void)setAdjustsFontSizeToFitHeight:(BOOL)adjustsFontSizeToFitHeight {
    NSNumber *number = [NSNumber numberWithBool:adjustsFontSizeToFitHeight];
    objc_setAssociatedObject(self, @selector(adjustsFontSizeToFitHeight), number, OBJC_ASSOCIATION_ASSIGN);
}

-(UIFont *)fontToFitHeight {
    float desiredHeight = [self frame].size.height;
    float guess;
    float guessHeight;

    guess = [[self font] pointSize];
    guessHeight = [self sizeIf:guess];
    if(guessHeight == desiredHeight) {
        return [[self font] fontWithSize:guess];
    }

    int attempts = 4;
    while(attempts > 0) {
        guess = guess * (desiredHeight / guessHeight);
        guessHeight = [self sizeIf:guess];

        if(guessHeight == desiredHeight) {
            return [[self font] fontWithSize:guess];
        }

        attempts--;
    }

    return [[self font] fontWithSize:guess];
}

-(float)sizeIf:(float)sizeToTry {
    CGSize size = [[self text] sizeWithAttributes:@{ NSFontAttributeName : [[self font] fontWithSize:sizeToTry] }];
    return size.height;
}

-(void)layoutSubviews {
    [super layoutSubviews];

    if([self adjustsFontSizeToFitHeight]) {
        [self setFont:[self fontToFitHeight]];
    }
}

像任何其他类别一样导入......

#import "UILabel+FitToHeight.h"

并使用如下......

UILabel *titleLabel = [[UILabel alloc] init];
[titleLabel setAdjustsFontSizeToFitHeight:YES];
[titleLabel setAdjustsFontSizeToFitWidth:YES];

值得注意的是,此仍然[titleLabel setAdjustsFontSizeToFitWidth:YES];一起使用,因此完全可以使用两者。

答案 12 :(得分:0)

道歉,如果我在所有文本中遗漏了一些内容。

我跟着@Crazyrems suggestions自动收集了标签的字体。这会根据其他人观察到的宽度来缩放字体。

然后我就设置了&#39; Lines&#39;在Xcode的UILabel字体部分中为0。在代码中,应该是numberOfLines。这就是全部。

归功于@Mikrasya,他在上述一条评论中暗示了这个解决方案。

在Xcode 7.3和iOS 9.3.2上测试。

答案 13 :(得分:0)

这似乎对我有用,我将UILabel子类化,并在layoutSubviews中检查了实际高度并相应地调整了字体大小。

import UIKit

class HeightAdjustableLabel: UILabel {

    override func layoutSubviews() {
        super.layoutSubviews()
        if frame.height < font.pointSize + 2 {
            font = font.withSize(frame.height - 2)
        }
    }
}

答案 14 :(得分:0)

接受的答案中包含错误。可变距离必须是浮点数,否则它可能返回的字体大小太大。另外,使用“-(CGSize)sizeWithFont:(UIFont *)font;”不推荐使用。这是修正了这两个问题的代码。

+ (UIFont *)findAdaptiveFontWithName:(NSString *)fontName forUILabelSize:(float)maxHeight withMaxFontSize:(int)maxFontSize
{
    UIFont *tempFont = nil;
    NSString *testString = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    NSInteger tempMin = 0;
    NSInteger tempMax = maxFontSize;
    NSInteger mid = 0;
    float difference = 0;

    while (tempMin <= tempMax) {
        mid = tempMin + (tempMax - tempMin) / 2;
        tempFont = [UIFont fontWithName:fontName size:mid];

        UILabel* dummyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
        dummyLabel.text = testString;
        dummyLabel.font = tempFont;
        [dummyLabel sizeToFit];

        difference = maxHeight - dummyLabel.bounds.size.height;

        if (mid == tempMin || mid == tempMax) {
            if (difference < 0) {
                return [UIFont fontWithName:fontName size:(mid - 1)];
            }

            return [UIFont fontWithName:fontName size:mid];
        }

        if (difference < 0) {
            tempMax = mid - 1;
        } else if (difference > 0) {
            tempMin = mid + 1;
        } else {
            return [UIFont fontWithName:fontName size:mid];
        }
    }

    return [UIFont fontWithName:fontName size:mid];
}

答案 15 :(得分:0)

Joel Fisher's epic answer为基础,但写为 Swift 4 扩展名:

extension String {

    /// Attempts to return the font specified by name of the appropriate point
    /// size for this string to fit within a particular container size and
    /// constrained to a lower and upper bound point size.
    /// - parameter name: of the font.
    /// - parameter containerSize: that this string should fit inside.
    /// - parameter lowerBound: minimum allowable point size of this font.
    /// - parameter upperBound: maximum allowable point size of this font.
    /// - returns: the font specified by name of the appropriate point
    /// size for this string to fit within a particular container size and
    /// constrained to a lower and upper bound point size; `nil` if no such
    /// font exists.
    public func font(named name: String,
                     toFit containerSize: CGSize,
                     noSmallerThan lowerBound: CGFloat = 1.0,
                     noLargerThan upperBound: CGFloat = 256.0) -> UIFont? {
        let lowerBound = lowerBound > upperBound ? upperBound : lowerBound
        let mid = lowerBound + (upperBound - lowerBound) / 2
        guard let tempFont = UIFont(name: name, size: mid) else { return nil }
        let difference = containerSize.height -
            self.size(withAttributes:
                [NSAttributedStringKey.font : tempFont]).height
        if mid == lowerBound || mid == upperBound {
            return UIFont(name: name, size: difference < 0 ? mid - 1 : mid)
        }
        return difference < 0 ? font(named: name,
                                     toFit: containerSize,
                                     noSmallerThan: mid,
                                     noLargerThan: mid - 1) :
            (difference > 0 ? font(named: name,
                                   toFit: containerSize,
                                   noSmallerThan: mid,
                                   noLargerThan: mid - 1) :
                UIFont(name: name, size: mid))
    }

    /// Returns the system font of the appropriate point size for this string
    /// to fit within a particular container size and constrained to a lower
    /// and upper bound point size.
    /// - parameter containerSize: that this string should fit inside.
    /// - parameter lowerBound: minimum allowable point size of this font.
    /// - parameter upperBound: maximum allowable point size of this font.
    /// - returns: the system font of the appropriate point size for this string
    /// to fit within a particular container size and constrained to a lower
    /// and upper bound point size.
    public func systemFont(toFit containerSize: CGSize,
                           noSmallerThan lowerBound: CGFloat = 1.0,
                           noLargerThan upperBound: CGFloat = 256.0) -> UIFont {
        let lowerBound = lowerBound > upperBound ? upperBound : lowerBound
        let mid = lowerBound + (upperBound - lowerBound) / 2
        let tempFont = UIFont.systemFont(ofSize: mid)
        let difference = containerSize.height -
            self.size(withAttributes:
                [NSAttributedStringKey.font : tempFont]).height
        if mid == lowerBound || mid == upperBound {
            return UIFont.systemFont(ofSize: difference < 0 ? mid - 1 : mid)
        }
        return difference < 0 ? systemFont(toFit: containerSize,
                                           noSmallerThan: mid,
                                           noLargerThan: mid - 1) :
            (difference > 0 ? systemFont(toFit: containerSize,
                                         noSmallerThan: mid,
                                         noLargerThan: mid - 1) :
                UIFont.systemFont(ofSize: mid))
    }

}

用法:

let font = "Test string".font(named: "Courier New",
                              toFit: CGSize(width: 150.0, height: 30.0),
                              noSmallerThan: 12.0,
                              noLargerThan: 20.0)
let sysfont = "Test string".systemFont(toFit: CGSize(width: 150.0, height: 30.0),
                                       noSmallerThan: 12.0,
                                       noLargerThan: 20.0)

答案 16 :(得分:0)

如果我错了,请原谅我,但这里提到的一切都是不必要的。使用yourLabel.height的新fontSize

在更改后立即重新设置字体

您还可以检查这些值(yourLabel.height和fontSize)之间的条件比较,以防止不必要的更新。

您需要做的就是:

[yourLabel setFont:[UIFont fontWithName:@"*your fontname*" size:yourLabel.frame.size.height]];

答案 17 :(得分:0)

SWIFT变体:

我设法用扩展程序做到了。工作正常,最小字体大小为5。 我从高处减去10,所以我也留下了“边距”,但你可以删除它或修改它。

extension UILabel {

//Finds and sets a font size that matches the height of the frame. 
//Use in case the font size is epic huge and you need to resize it.
func resizeToFitHeight(){
    var currentfontSize = font.pointSize
    let minFontsize = CGFloat(5)
    let constrainedSize = CGSizeMake(frame.width, CGFloat.max)

    while (currentfontSize >= minFontsize){
        let newFont = font.fontWithSize(currentfontSize)
        let attributedText: NSAttributedString = NSAttributedString(string: text!, attributes: [NSFontAttributeName: newFont])
        let rect: CGRect = attributedText.boundingRectWithSize(constrainedSize, options: .UsesLineFragmentOrigin, context: nil)
        let size: CGSize = rect.size

        if (size.height < frame.height - 10) {
            font = newFont
            break;
        }

        currentfontSize--
    }

    //In case the text is too long, we still show something... ;)
    if (currentfontSize == minFontsize){
        font = font.fontWithSize(currentfontSize)
    }
}

}

答案 18 :(得分:0)

对于大型/小型设备按比例调整大小的UILabel:

对我来说最有效的解决方案是将字体的磅值设置为标签高度+/-调整系数的某个比例。假设使用自动布局约束,将其垂直中心对齐到超视图的底部,乘以比率。同样在IB中,将标签的宽度约束为屏幕宽度的一部分。

或者,您可以使用宽高比约束锁定标签的高度/宽度比,但如果您没有正确获得字体的磅值计算,则可能会导致剪裁。锁定纵横比的唯一原因是其他控件/视图的位置是否与此标签相关。但是我强烈建议相对于superview的高度/宽度放置这样的控件/视图,以便它们不依赖于此标签。

我知道这不是一个封装的解决方案,但它一直让我感到悲伤最少。唯一接近的解决方案是使用while循环,但在我的情况下,我无法处理它们对每个布局/刷新系统调用施加的延迟。

答案 19 :(得分:-1)

我做了一个宏来为你做

///Scales FontSize up (or down) until the text fits within the height of the label, will not auto-update, must be called any time text is updated. Label Frame must be set prior to calling
#define scaleFontSizeToFillHeight(__label) {\
__label.font = [UIFont fontWithName:__label.font.fontName size:__label.frame.size.height*2.0f];\
UIFont *__currentFont = __label.font;\
CGFloat __originalFontSize = __currentFont.pointSize;\
CGSize __currentSize = [__label.text sizeWithAttributes:@{NSFontAttributeName : __currentFont}];\
while (__currentSize.height > __label.frame.size.height && __currentFont.pointSize > (__originalFontSize * __label.minimumScaleFactor)) {\
__currentFont = [__currentFont fontWithSize:__currentFont.pointSize - 1];\
__currentSize = [__label.text sizeWithAttributes:@{NSFontAttributeName : __currentFont}];\
}\
__label.font = __currentFont;\
}

答案 20 :(得分:-7)

是的,转到界面构建器,(您的.xib文件)并转到属性检查器右侧的第三个选项卡,您可以在那里设置字体的大小!