iOS UILabel自动收缩,因此单词不会截断为两行

nor*_*rry 5 objective-c interface-builder uilabel ios

我正在尝试缩小UILabel,以使单词不会截断到下一行。不仅仅是文本在文本区域的末尾被截断。

如果我有一个50x100的盒子,而我想在25.0pt的盒子里放类似“美国”的东西,我最终会得到:

   50px
 -------
|Ameri- |
|can    |
|Beauty | 100px
|       |
 -------
Run Code Online (Sandbox Code Playgroud)

在这种情况下,文本收缩似乎没有任何作用,因为它仍然适合UILabel框架。当文本很长时,例如“ Willie Wonka的Chocolate Factory”,它会很好地工作,但是我不希望单词被截断。

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

    50px
 --------
[American|
|Beauty  | 100px
|        |
|        |
|        |
 --------
Run Code Online (Sandbox Code Playgroud)

任何建议将不胜感激!

编辑:解决方案

由于以下答案中的建议,这就是我最后要做的事情。效果很好!

- (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;
}
Run Code Online (Sandbox Code Playgroud)

Dam*_*Dam 5

只是添加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
    }
}
}
Run Code Online (Sandbox Code Playgroud)


Tom*_*mmy 2

我想不出任何直接内置的东西。所以我建议:

[NSCharacterSet +whitespaceAndNewlineCharacterSet]通过和将字符串拆分为多个部分[NSString -componentsSeparatedByCharactersInSet:]。我考虑过建议更高级别的人NSLinguisticTagger输出整个单词,但这不允许像末尾带有冒号的单词这样的东西。

在这些单词中,使用 UIKit 添加NSString -sizeWithAttributes:(在 iOS 7 下)或-sizeWithFont:(在 6 或更低版本下)查找排版上最大的单词。你会假设当你缩小字体大小时,最大的仍然是最大的,我认为这永远是正确的,因为苹果不会做激进的字体提示。

如果该单词的宽度已经小于您视图的宽度,那么您就完成了。只需显示字符串即可。

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