iOS UILabel自动收缩所以单词不会截断为两行

时间:2014-04-16 22:23:26

标签: ios objective-c interface-builder uilabel

我试图让UILabel缩小,以免词语截断到下一行。不只是在文本区域末尾截断文本。

如果我有一个50x100的盒子,我想要输入像#34; American"在25.0pt的方框中,我最终得到了:

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

在这种情况下,文字缩小似乎没有做任何事情,因为它仍然适合UILabel框架。当文本非常长,如Willie Wonka的巧克力工厂"时,它的效果非常好,但我不想截断文字。

这是该场景中的理想输出:

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

任何建议都会超级适用!

编辑:解决方案

由于下面答案中的建议,我最终做了以下事情。它很棒!

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

4 个答案:

答案 0 :(得分:4)

只是添加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
    }
}
}

答案 1 :(得分:2)

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

[NSCharacterSet +whitespaceAndNewlineCharacterSet][NSString -componentsSeparatedByCharactersInSet:]将字符串拆分为组件。我考虑过推荐更高级别的NSLinguisticTagger以获得完整的单词,但这样就不会允许像结尾的单词这样的内容。

在这些词中,使用UIKit添加NSString -sizeWithAttributes:(在iOS 7下)或-sizeWithFont:(在6或以下)找到排版最大的词。当你缩小字体大小时,你会假设最大值仍然是最大的,我认为这总是正确的,因为Apple没有做出激进的字体提示。

如果该字的宽度已经不如您的视图宽度,那么您就完成了。只需显示字符串。

否则使用快速二进制搜索,反复查询大小,直到找到你认为合适的精度所需的较小字体大小(0.1分对我来说听起来很合理,但你明白了)。然后以该大小显示整个字符串。

答案 2 :(得分:0)

我做了一个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
    }
}
} 

答案 3 :(得分:0)

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