iOS UILabel autoshrink,所以单词不会被截断为两行

我试图让UILabel缩小,以便单词不会被截断到下一行。 不只是文本截断在文本区域的末尾。

如果我有一个50×100的盒子,我想在25.0pt的盒子里放一些“美式”的东西,那么我得到:

50px ------- |Ameri- | |can | |Beauty | 100px | | ------- 

在这种情况下,文本缩小似乎没有做任何事情,因为它仍然适合UILabel框架。 如果文本真的很长,像“Willie Wonka的巧克力工厂”,但是我不想截词。

这是这种情况下的理想输出:

  50px -------- [American| |Beauty | 100px | | | | | | -------- 

任何build议将超级appreicated!

编辑:解决scheme

以下是答案中的build议。 这很好用!

 - (CGFloat) calculateFromUILabel:(UILabel *)label { NSString *stringToMeasure = label.text; NSLog(@"FontSizeMeasurement.calculateFromUILabel() %@", stringToMeasure); NSRange range = NSMakeRange(0, 1); NSAttributedString *attributedString = label.attributedText; NSDictionary *attributes = [attributedString attributesAtIndex:0 effectiveRange:&range]; NSMutableCharacterSet *characterSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy]; [characterSet addCharactersInString:@"-"]; NSArray *words = [stringToMeasure componentsSeparatedByCharactersInSet:characterSet]; CGSize maxSize = CGSizeZero; NSMutableAttributedString *maxWidthString = nil; for(int i = 0; i < words.count; i++) { NSString *word = words[i]; CGSize wordSize = [word sizeWithAttributes:attributes]; if(wordSize.width > maxSize.width) { maxSize = wordSize; maxWidthString = [[NSMutableAttributedString alloc] initWithString:word attributes:attributes]; } } UIFont *font = [label.font copy]; while(maxSize.width > self.maxWidth) { font = [font fontWithSize:(font.pointSize-0.1)]; [maxWidthString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, maxWidthString.length)]; maxSize = [maxWidthString size]; } return font.pointSize; } 

我可以想象没有直接内置的东西。所以我build议:

通过[NSCharacterSet +whitespaceAndNewlineCharacterSet][NSString -componentsSeparatedByCharactersInSet:] [NSCharacterSet +whitespaceAndNewlineCharacterSet] [NSString -componentsSeparatedByCharactersInSet:]将string拆分为组件。 我考虑推荐更高级别的NSLinguisticTagger去掉整个单词,但是不允许像冒号的单词那样的东西。

在这些词语中,使用UIKit添加NSString -sizeWithAttributes:在iOS 7下)或-sizeWithFont:在6或以下)可以find印刷最大的字体。 当你缩小字体大小的时候,你会做出这样的假设,即最大的字体仍然是最大的,我认为这将永远是真实的,因为苹果公司并没有进行激进的字体暗示。

如果这个词已经不是你视图的宽度,那么你就完成了。 只显示string。

否则,使用快速二分search,反复查询大小,直到find所需的较小字体大小,以您认为合适的精度(0.1的点对我来说听起来合理,但您明白了这一点)。 然后显示整个string的大小。

我做了一个UILabel的Swift扩展。 设置边界和文本后,只需将方法调用到标签即可。

 extension UILabel { func fitToAvoidWordWrapping(){ // adjusts the font size to avoid long word to be wrapped // get text as NSString let text = self.text ?? "" as NSString // get array of words separate by spaces let words = text.componentsSeparatedByString(" ") as! [NSString] // I will need to find the largest word and its width in points var largestWord : NSString = "" var largestWordWidth : CGFloat = 0 // iterate over the words to find the largest one for word in words{ // get the width of the word given the actual font of the label let wordSize = word.sizeWithAttributes([NSFontAttributeName : self.font]) let wordWidth = wordSize.width // check if this word is the largest one if wordWidth > largestWordWidth{ largestWordWidth = wordWidth largestWord = word } } // now that I have the largest word, reduce the label's font size until it fits while largestWordWidth > self.bounds.width && self.font.pointSize > 1{ // reduce font and update largest word's width self.font = self.font.fontWithSize(self.font.pointSize - 1) let largestWordSize = largestWord.sizeWithAttributes([NSFontAttributeName : self.font]) largestWordWidth = largestWordSize.width } } } 

SWIFT 3以上扩展的翻译。 奇迹般有效!

 extension UILabel { func fitToAvoidWordWrapping(){ // adjusts the font size to avoid long word to be wrapped // get text as NSString let text = self.text ?? ("" as NSString) as String // get array of words separate by spaces let words = text.components(separatedBy: " ") // I will need to find the largest word and its width in points var largestWord : NSString = "" var largestWordWidth : CGFloat = 0 // iterate over the words to find the largest one for word in words{ // get the width of the word given the actual font of the label let wordSize = word.size(attributes: [NSFontAttributeName : self.font]) let wordWidth = wordSize.width // check if this word is the largest one if wordWidth > largestWordWidth{ largestWordWidth = wordWidth largestWord = word as NSString } } // now that I have the largest word, reduce the label's font size until it fits while largestWordWidth > self.bounds.width && self.font.pointSize > 1{ // reduce font and update largest word's width self.font = self.font.withSize(self.font.pointSize - 1) let largestWordSize = largestWord.size(attributes: [NSFontAttributeName : self.font]) largestWordWidth = largestWordSize.width } } } 

只是添加Swift 4版本+添加一个警卫,只做adjustsFontSizeToFitWidth true,因为使用false的用户不会希望长字符合我想。

 extension UILabel { // Adjusts the font size to avoid long word to be wrapped func fitToAvoidWordWrapping() { guard adjustsFontSizeToFitWidth else { return // Adjust font only if width fit is needed } guard let words = text?.components(separatedBy: " ") else { return // Get array of words separate by spaces } // I will need to find the largest word and its width in points var largestWord: NSString = "" var largestWordWidth: CGFloat = 0 // Iterate over the words to find the largest one for word in words { // Get the width of the word given the actual font of the label let wordWidth = word.size(withAttributes: [.font: font]).width // check if this word is the largest one if wordWidth > largestWordWidth { largestWordWidth = wordWidth largestWord = word as NSString } } // Now that I have the largest word, reduce the label's font size until it fits while largestWordWidth > bounds.width && font.pointSize > 1 { // Reduce font and update largest word's width font = font.withSize(font.pointSize - 1) largestWordWidth = largestWord.size(withAttributes: [.font: font]).width } } }