用多行自动缩放UILabel

是否可以在UILabel多行上使用autoshrink属性? 例如,在可用的两行上可能有较大的文本大小。

这些人find了解决办法:

http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/

他们的解决scheme如下:

 int maxDesiredFontSize = 28; int minFontSize = 10; CGFloat labelWidth = 260.0f; CGFloat labelRequiredHeight = 180.0f; //Create a string with the text we want to display. self.ourText = @"This is your variable-length string. Assign it any way you want!"; /* This is where we define the ideal font that the Label wants to use. Use the font you want to use and the largest font size you want to use. */ UIFont *font = [UIFont fontWithName:@"Marker Felt" size:maxDesiredFontSize]; int i; /* Time to calculate the needed font size. This for loop starts at the largest font size, and decreases by two point sizes (i=i-2) Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */ for(i = maxDesiredFontSize; i > minFontSize; i=i-2) { // Set the new font size. font = [font fontWithSize:i]; // You can log the size you're trying: NSLog(@"Trying size: %u", i); /* This step is important: We make a constraint box using only the fixed WIDTH of the UILabel. The height will be checked later. */ CGSize constraintSize = CGSizeMake(labelWidth, MAXFLOAT); // This step checks how tall the label would be with the desired font. CGSize labelSize = [self.ourText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; /* Here is where you use the height requirement! Set the value in the if statement to the height of your UILabel If the label fits into your required height, it will break the loop and use that font size. */ if(labelSize.height <= labelRequiredHeight) break; } // You can see what size the function is using by outputting: NSLog(@"Best size is: %u", i); // Set the UILabel's font to the newly adjusted font. msg.font = font; // Put the text into the UILabel outlet variable. msg.text = self.ourText; 

为了得到这个工作,一个IBOutlet必须在接口生成器中分配给UILabel。

“IBOutlet UILabel * msg;”

所有的优点是在11像素的人。

我修改了上面的代码,使其成为UILabel上的一个类别:

头文件:

 #import <UIKit/UIKit.h> @interface UILabel (MultiLineAutoSize) - (void)adjustFontSizeToFit; @end 

并执行文件:

 @implementation UILabel (MultiLineAutoSize) - (void)adjustFontSizeToFit { UIFont *font = self.font; CGSize size = self.frame.size; for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumFontSize; maxSize -= 1.f) { font = [font fontWithSize:maxSize]; CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; if(labelSize.height <= size.height) { self.font = font; [self setNeedsLayout]; break; } } // set the font to the minimum size anyway self.font = font; [self setNeedsLayout]; } @end 

我发现这个链接http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/

这个问题可以用三个简单的步骤使用Interface Builder来解决:

  1. 将“自动缩放”设置为“最小字体大小”。
  2. 将字体设置为您想要的最大字体大小(20),并将行设置为,比如10,在我的情况下,字体大小与标签中的行数相同。
  3. 然后,将“换行”从“换行”改为“截尾”。

希望能帮助到你!

这是根据iOS的itecedor更新更新到iOS 7的类别解决scheme。

头文件:

 #import <UIKit/UIKit.h> @interface UILabel (MultiLineAutoSize) - (void)adjustFontSizeToFit; @end 

并执行文件:

 @implementation UILabel (MultiLineAutoSize) - (void)adjustFontSizeToFit { UIFont *font = self.font; CGSize size = self.frame.size; for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f) { font = [font fontWithSize:maxSize]; CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); CGRect textRect = [self.text boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil]; CGSize labelSize = textRect.size; if(labelSize.height <= size.height) { self.font = font; [self setNeedsLayout]; break; } } // set the font to the minimum size anyway self.font = font; [self setNeedsLayout]; } @end 

标记为解决scheme的答案是hacky和不精确的。 如果您正确设置以下属性,UILabel将自动处理它:

numberOfLines必须是非零

adjustsFontSizeToFitWidth必须是YES

lineBreakMode一定不能NSLineBreakByCharWrappingNSLineBreakByWordWrapping

由于缺乏声誉,我不能评论MontiRabbit的post,所以我会做出一个新的答案。 他(和她的推荐人)提出的解决scheme在Xcode 7.3或更高版本上不起作用,这是不准确的。 为了使它工作,在故事板,我不得不:

  1. 设置宽度约束(纯宽度或尾部和导程)
  2. 设置高度约束(这是非常重要的,通常使用自动resize,不设置标签高度)
  3. 将“Autoshrink”属性设置为“最小字体大小”或“最小字体大小”(适用于两种情况)
  4. 将“换行符”属性设置为“截断尾巴”
  5. 将“Lines”属性设置为非零值

希望能帮助到你! ;)

从@DaGaMs改编的快速版本。

SWIFT 2:

 extension UILabel { func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) { let maxFontSize = maximumFontSize ?? font.pointSize for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) { let proposedFont = font.fontWithSize(size) let constraintSize = CGSizeMake(bounds.size.width, CGFloat(MAXFLOAT)) let labelSize = ((text ?? "") as NSString).boundingRectWithSize(constraintSize, options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: proposedFont], context: nil) if labelSize.height <= bounds.size.height { font = proposedFont setNeedsLayout() break; } } } } 

SWIFT 3:

 extension UILabel { func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) { let maxFontSize = maximumFontSize ?? font.pointSize for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) { let proposedFont = font.withSize(size) let constraintSize = CGSize(width: bounds.size.width, height: CGFloat(MAXFLOAT)) let labelSize = ((text ?? "") as NSString).boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: proposedFont], context: nil) if labelSize.height <= bounds.size.height { font = proposedFont setNeedsLayout() break; } } } } 

我喜欢DaGaMs的答案,但在使用UITableViewCells中的标签可能会返回dequeueReusableCell:,正常的字体大小将继续缩小,即使原始字体大小仍然是一些tableView单元格,文本less,可以利用原始标签的原始字体大小。

所以,我以DaGaMs的类别作为起点,我创build了一个单独的类,而不是一个单独的类,我确保我的故事板中的UILabels使用这个新类:

 #import "MultiLineAutoShrinkLabel.h" @interface MultiLineAutoShrinkLabel () @property (readonly, nonatomic) UIFont* originalFont; @end @implementation MultiLineAutoShrinkLabel @synthesize originalFont = _originalFont; - (UIFont*)originalFont { return _originalFont ? _originalFont : (_originalFont = self.font); } - (void)quoteAutoshrinkUnquote { UIFont* font = self.originalFont; CGSize frameSize = self.frame.size; CGFloat testFontSize = _originalFont.pointSize; for (; testFontSize >= self.minimumFontSize; testFontSize -= 0.5) { CGSize constraintSize = CGSizeMake(frameSize.width, MAXFLOAT); CGSize testFrameSize = [self.text sizeWithFont:(font = [font fontWithSize:testFontSize]) constrainedToSize:constraintSize lineBreakMode:self.lineBreakMode]; // the ratio of testFontSize to original font-size sort of accounts for number of lines if (testFrameSize.height <= frameSize.height * (testFontSize/_originalFont.pointSize)) break; } self.font = font; [self setNeedsLayout]; } @end 

被引用的答案有一个问题,就是pwightman指出的。 而且,不需要修整空格。 这里是修改后的版本:

 - (void)adjustFontSizeToFit { UIFont *font = self.font; CGSize size = self.frame.size; for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f) { font = [font fontWithSize:maxSize]; CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping]; if(labelSize.height <= size.height) { self.font = font; [self setNeedsLayout]; break; } } // set the font to the minimum size anyway self.font = font; [self setNeedsLayout]; } 

感谢DaGaMs为这个解决scheme。

我已经更新如下:

1 – 使用iOS 6(因为不推荐使用minimumFontSize和UILineBreakModeWordWrap)2 – 从标签的文本中去除空格,因为这会导致resize失败(您不想知道多久才能findBUG)

 -(void)adjustFontSizeToFit { self.text = [self.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; UIFont *font = self.font; CGSize size = self.frame.size; for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor; maxSize -= 1.f) { font = [font fontWithSize:maxSize]; CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT); CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping]; if(labelSize.height <= size.height) { self.font = font; [self setNeedsLayout]; break; } } // set the font to the minimum size anyway self.font = font; [self setNeedsLayout]; } 

为了实现这个function,我在上面的“The Dude's”答案中写了一个UILabel的小类。

https://gist.github.com/ayushn21/d87b835b2efc756e859f

对于UIButton,只是这些线为我工作:

 self.centerBtn.titleLabel.numberOfLines = 2; self.centerBtn.titleLabel.textAlignment = NSTextAlignmentCenter; self.centerBtn.titleLabel.adjustsFontSizeToFitWidth = YES; 

NSString上有一个方法, -sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:从iOS 2.0开始显然已经存在,但不幸的是在iOS 7中不推荐使用,因为不鼓励自动缩小字体大小。 我真的不明白苹果在这方面的立场,因为他们在keynote等使用它,我认为如果字体大小在一个小范围内,这是没问题的。 这里是使用这种方法在Swift中的一个实现。

 var newFontSize: CGFloat = 30 let font = UIFont.systemFontOfSize(newFontSize) (self.label.text as NSString).sizeWithFont(font, minFontSize: 20, actualFontSize: &newFontSize, forWidth: self.label.frame.size.width, lineBreakMode: NSLineBreakMode.ByWordWrapping) self.label.font = font.fontWithSize(newFontSize) 

我不知道这种方式可以实现,而不使用不推荐的方法。

我使用了@Wbarksdale的Swift 3解决scheme,但是发现中间有很长的文字被截断了。 为了保持文字完整,我不得不修改如下所示:

 extension UILabel { func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) { let maxFontSize = maximumFontSize ?? font.pointSize let words = self.text?.components(separatedBy: " ") var longestWord: String? if let max = words?.max(by: {$1.characters.count > $0.characters.count}) { longestWord = max } for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) { let proposedFont = font.withSize(size) let constraintSize = CGSize(width: bounds.size.width, height: CGFloat(MAXFLOAT)) let labelSize = ((text ?? "") as NSString).boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: proposedFont], context: nil) let wordConstraintSize = CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT)) let longestWordSize = ((longestWord ?? "") as NSString).boundingRect(with: wordConstraintSize, options: .usesFontLeading, attributes: [NSFontAttributeName: proposedFont], context: nil) if labelSize.height <= bounds.size.height && longestWordSize.width < constraintSize.width { font = proposedFont setNeedsLayout() break } } } } 

尝试这个:

在设置标签上的文本属性后,可以调用UILabel子类或调用adjustFontSize方法

 override var text : String? { didSet { self.adjustFontSize() } } func adjustFontSize() { var lineCount = self.string.components(separatedBy: "\n").count - 1 var textArray = self.string.components(separatedBy: " ") var wordsToCompare = 1 while(textArray.count > 0) { let words = textArray.first(n: wordsToCompare).joined(separator: " ") let wordsWidth = words.widthForHeight(0, font: self.font) if(wordsWidth > self.frame.width) { textArray.removeFirst(wordsToCompare) lineCount += 1 wordsToCompare = 1 } else if(wordsToCompare > textArray.count) { break } else { wordsToCompare += 1 } } self.numberOfLines = lineCount + 1 }