如何知道UILabel中的单词是否被删除

时间:2015-03-05 16:14:50

标签: ios objective-c

我尝试开发自动收缩功能。我已将文字归因于固定大小UILabel。之后我降低字体大小并检查文本是否适合给定的容器大小。

问题是如果单词长度超过容器宽度,则UILabel会忽略NSLineBreakByWordWrapping。导致我削减了尾词。

以下是代码:

- (void) setCardText:(NSString *)txt {
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:txt];
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
    [paragraphStyle setAlignment:NSTextAlignmentCenter];
    [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [txt length])];
    self.cardLabel.attributedText = attributedString;

    for (CGFloat fontSize = 40; fontSize >=5; fontSize--) {
        [self.cardLabel setFont:[UIFont fontWithName:@"GothamPro-Light" size:fontSize]];
        [paragraphStyle setLineSpacing:fontSize*0.3f];
        [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [txt length])];
        self.cardLabel.lineBreakMode = NSLineBreakByWordWrapping;
        [self.cardLabel sizeToFit];
        if (self.cardLabel.frame.size.width <= 220) {
            [self.cardLabel setFrame:CGRectMake(40, 40, 220, self.cardLabel.frame.size.height)];
        }
        if (self.cardLabel.frame.size.height <= 210) {
            [self.cardLabel setFrame:CGRectMake(40, 40, self.cardLabel.frame.size.width, 210)];
        }
        if (self.cardLabel.frame.size.width <= 220 && self.cardLabel.frame.size.height <= 210) {
            [self.cardLabel setFrame:CGRectMake(40, 40, 220, 210)];
            break;
        }
    };

这是结果(我很抱歉用俄语截图):http://take.ms/kg2mG

在第三行中,单词被剪切,其结尾移动到下一行。

我想这是因为最初这个词不适合容器宽度而被强行分成两半。我想我需要一种切词检测器,它告诉我要不断降低字体大小。或者另一个猜测是迫使UILabel被“不合适的词”扩展。但我找不到任何可以做这项工作的东西。

此外,我可以将给定的字符串分解为单词并检查它们中的每一个是否适合容器宽度。但我认为这种方法是一种轮子发明。我错过了哪些可以轻松解决我的问题?

2 个答案:

答案 0 :(得分:1)

方法sizeToFit调用sizeThatFits:返回“最佳”大小以适合当前边界,然后调整标签大小。所以首先你约束标签,它必须适合给定的宽度。你可以看到NSLineBreakByWordWrapping的描述 - 包装发生在单词边界,除非单词本身不适合单行。

出于您的目的,您应该允许标签适合明显比其要求更宽的宽度。但这很困难,因为任务是找到最好的字体大小,我们无法预测宽度。最好的方法是根据文本中最长的单词找到字体大小。

所以算法:

  1. 通过用空格分隔来检测最长的单词。
  2. 迭代地,减小字体大小并计算最长单词的大小,而单词大于所需宽度。
  3. 将计算字体设置为全文并调用sizeThatFits。
  4. 请找下面的示例代码(&#34; Verdana&#34;字体用于测试)

    - (void) setText {
        NSString * text = @"Incidental, indirect, secondary, side rival - Побочный, косвенный, второстепенный, боковой соперник";
        CGFloat maxWidth = 300.;
        [self setText:text toLabel:self.label maxWidth:maxWidth];
    }
    
    - (void) setText:(NSString *)text
             toLabel:(UILabel*)label
            maxWidth:(CGFloat)maxWidth
    {
        CGFloat fontSize = [self fontSizeOfWord:[self theLongestWord:text]
                                initialFontSize:40.
                             constrainedByWidth:maxWidth];
    
        NSMutableAttributedString * attributedString = [self attributedStringForText:text];
        [self setupAttributedStirng:attributedString withFontWithSize:fontSize];
        label.attributedText = attributedString;
        CGRect labelFrame = label.frame;
        labelFrame.size = [label sizeThatFits:[attributedString sizeAdaptedForWidth:maxWidth]];
        label.frame = labelFrame;
    }
    
    - (NSString*) theLongestWord:(NSString*)text {
        NSArray * words = [text componentsSeparatedByString:@" "];
        NSUInteger longestLength = 0;
        NSUInteger index = NSNotFound;
        for(int i = 0; i < words.count; i++) {
            NSString * word = words[i];
            CGFloat length = word.length;
            if(length > longestLength) {
                longestLength = length;
                index = i;
            }
        }
        return (index != NSNotFound ? words[index] : nil);
    }
    
    - (CGFloat)fontSizeOfWord:(NSString *)word
              initialFontSize:(CGFloat)initialFontSize
           constrainedByWidth:(CGFloat)maxWidth
    {
        NSMutableAttributedString * wordString = [self attributedStringForText:word];
        CGFloat fontSize = initialFontSize;
        for (; fontSize >= 5.; --fontSize) {
            [self setupAttributedStirng:wordString
                       withFontWithSize:fontSize];
            CGSize wordSize = [wordString sizeAdaptedForWidth:CGFLOAT_MAX];
            if(wordSize.width <= maxWidth){
                break;
            }
        }
        return fontSize;
    }
    
    - (NSMutableAttributedString*) attributedStringForText:(NSString*)text {
        return (text&&text.length ? [[NSMutableAttributedString alloc] initWithString:text]:nil);
    }
    
    - (void)setupAttributedStirng:(NSMutableAttributedString *)attributedString
                 withFontWithSize:(CGFloat)fontSize
    {
        NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
        [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
        [paragraphStyle setAlignment:NSTextAlignmentCenter];
        UIFont * font = [UIFont fontWithName:@"Verdana" size:fontSize];
        [paragraphStyle setLineSpacing:fontSize*0.3f];
        NSDictionary * attributes = @{NSParagraphStyleAttributeName: paragraphStyle,
                                      NSFontAttributeName: font};
        [attributedString addAttributes:attributes
                                  range:NSMakeRange(0, [attributedString length])];
    }
    

    NSAttributedString的类别:

    @implementation NSAttributedString (AdaptedSize)
    
    - (CGSize) sizeAdaptedForWidth:(CGFloat)width
    {
        CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self);
        CGSize targetSize = CGSizeMake(width, CGFLOAT_MAX);
        CGSize fitSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,
                                                                      CFRangeMake(0, [self length]),
                                                                      NULL, targetSize, NULL);
        CFRelease(framesetter);
        return fitSize;
    }
    
    @end
    

答案 1 :(得分:0)

您是否尝试过UILabel.adjustsFontSizeToWidth属性?