iPhone UILabel sizeWithFont:

后端 未结 5 1164
刺人心
刺人心 2020-12-09 06:37

I\'m trying to measure the visual size of a NSString that takes into account the number of lines I can render. However, sizeWithFont doesn\'t take into account numberOfLines

相关标签:
5条回答
  • 2020-12-09 07:14

    Instead of CGFLOAT_MAX for the max height of your text calculation, try getting the size of one line with this:

    [_price.text sizeWithFont:_price.font].height
    

    and then multiplying that by the maximum # of lines you want, then plugging that into the height of the size you are constraining yourself to. It'd probably look like this:

    _price = [[UILabel alloc] init];
    _price.text = myPriceValue;
    _price.lineBreakMode = UILineBreakModeWordWrap;
    _price.numberOfLines = 3;
    _price.backgroundColor = [UIColor clearColor];
    _price.textColor = TTSTYLEVAR(colorPrice);
    CGFloat lineHeight = [_price.text sizeWithFont:_price.font].height;
    CGSize priceSize = [_price.text sizeWithFont:_price.font
            constrainedToSize:CGSizeMake(maxWidth, lineHeight * _price.numberOfLines)
            lineBreakMode:UILineBreakModeWordWrap];
    

    Don't use this if you ever set number of lines to 0 as your max height will be 0 in that case; you should use CGFLOAT_MAX then.

    0 讨论(0)
  • 2020-12-09 07:27

    Use the UILabel's sizeToFit instead of sizeWithFont: to layout a multi-line UILabel, since sizeWithFont: will truncate the string (see apple docs). The following code reduces the font size of a label until the text fit into a the specified size... multiple lines of text will be used as soon as they fit into the specified height:

    -(void)setFontSizeOfMultiLineLabel: (UILabel*)label 
            toFitSize: (CGSize) size 
            forMaxFontSize: (CGFloat) maxFontSize 
            andMinFontSize: (CGFloat) minFontSize 
            startCharacterWrapAtSize: (CGFloat)characterWrapSize{
    
    CGRect constraintSize = CGRectMake(0, 0, size.width, 0);
    label.frame = constraintSize;
    label.lineBreakMode = UILineBreakModeWordWrap;
    label.numberOfLines = 0; // allow any number of lines
    
    for (int i = maxFontSize; i > minFontSize; i--) {
    
        if((i < characterWrapSize) && (label.lineBreakMode == UILineBreakModeWordWrap)){
            // start over again with lineBreakeMode set to character wrap 
            i = maxFontSize;
            label.lineBreakMode = UILineBreakModeCharacterWrap;
        }
    
        label.font = [label.font fontWithSize:i];
        [label sizeToFit];
        if(label.frame.size.height < size.height){
            break;
        }       
        label.frame = constraintSize;
      } 
    }
    

    Call this with a label that has your favorite text and font:

    UILabel *label = [[UILabel alloc] initWithFrame: CGRectZero];   
    label.backgroundColor = [UIColor clearColor];   
    label.textColor = [UIColor whiteColor];
    label.text = text;
    label.font = [UIFont fontWithName: @"Helvetica" size: 16];
    [self setFontSizeOfMultiLineLabel: label toFitSize: CGSizeMake(200, 44) forMaxFontSize: 16 andMinFontSize: 8 startCharacterWrapAtSize: 11]; 
    

    The startCharacterWrapAtSize parameter lets you choose to use characterWrap starting at the giving font size. This should save space in the case wordWrap would use really small fonts.

    edit: bugfix

    0 讨论(0)
  • 2020-12-09 07:29

    Instead of trying to do it in one call, do something like this (pardon the pseudocode, it's late):

    NSString *s = _price.text;
    UIFont *font = _price.font;
    CGFloat fontSize = font.pointSize;
    
    while (TRUE)
    {
       CGSize priceSize = [s sizeWithFont: font constrainedToSize: 
           CGSizeMake(maxWidth, fontSize) lineBreakMode: UILineBreakModeWordWrap];
    
        if ( /* priceSize is satisfactory */ )
        {
            break; // Make sure this exits, eventually!!!
        }
        fontSize -= 1.0; // or a smaller decrement if you like
        font = // new, smaller font
    
    }
    
    0 讨论(0)
  • 2020-12-09 07:32

    The correct answer is, of course, you need to set numberOfLines to 0, which will cause the framework to compute the result with however many lines it needs. See also this question.

    0 讨论(0)
  • 2020-12-09 07:34

    Of course it doesn't take it into account, since nothing being called or passed in has that information. You're strictly working with strings, sizes, and fonts. It's the label that has the number of lines in it.

    I'm not sure what exactly your problem is; are you getting a size that's too tall or too short, or what? You can find out the number of lines of text by dividing the height of the result by the height of the font, which is the value of the ascender plus the descender, I believe.

    0 讨论(0)
提交回复
热议问题