What is -[NSString sizeWithFont:forWidth:lineBreakMode:] good for?

后端 未结 4 1640
难免孤独
难免孤独 2020-11-28 22:51

In my question \"How do I get -[NSString sizeWithFont:forWidth:lineBreakMode:] to work?\", I learned that -[NSString sizeWithFont:constrainedToSize:lineBreakMode:]

相关标签:
4条回答
  • 2020-11-28 23:19

    It works great for multi line strings as well.

    Basically its a function that lets you see how big a string is going to be when rendered with a font and line break mode.

    I use it in a few spots in my application when I have variable length text I want to display in a certain area.

    By default a UILabel will center the text vertically. To have the text top aligned you need to size the label to be only the height required by the string that's in it.

    I use this method to do this.

    And example of how I would use it to do that is as follows:

    //Calculate the expected size based on the font and linebreak mode of your label
    CGSize maximumLabelSize = CGSizeMake(296,9999);
    
    CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font 
                            constrainedToSize:maximumLabelSize 
                            lineBreakMode:yourLabel.lineBreakMode]; 
    
    //adjust the label the the new height.
    CGRect newFrame = yourLabel.frame;
    newFrame.size.height = expectedLabelSize.height;
    yourLabel.frame = newFrame;
    

    You specify how big of an area you have to put the text in, and then this method tells you how much space it will take up (wrapping as required). Also if the string will overflow the bounds of the rect you provide you can tell and then decided how to display the text.

    The reference to it not actually wrapping the text is there because this method doesn't actually do anything to the text. It just virtually lays it out and returns how big of an area it would need to really lay it out.

    its the responsibility of the label (or what ever container you are using for the text) to perform the wrapping/what ever else that needs to be done.

    Hope that helps.

    chris.

    0 讨论(0)
  • 2020-11-28 23:20

    For a while I thought this routine was simply broken. It sounds like it's the perfect routine for working out how high a piece of text is, when wrapped at a certain width. However this is not what it does. Indeed, the height returned is always a single line. (Which is pointless, incidentally: UIFont's -leading returns the same value.)

    To quote the documentation at the time of writing:

    Although it computes where line breaks would occur, this method does not actually wrap the text to additional lines; [...]

    This sentence confused me for a long time. My thoughts ran along the lines of:

    • Computing line-breaks, but not wrapping. Eh?
    • Maybe they mean the receiving NSString itself won't be mutated to reflect line-breaks? But I don't expect that anyway?
    • This sentence is not consistent with itself. I have no choice but to ignore it.

    However, it turns out there's a meaning that matches the behaviour we see. It seems that what they mean is:

    This routine will compute where the first line-break will occur, and all text after this is ignored for the purposes of calculating the bounding box.

    The bounding box returned will therefore have the height of a single line and a width up to the maximum specified. (The width may be less depending on where the line-break is calculated, or if the text is short enough that it does not need the maximum width.)

    To, um, answer the actual question: What is it good for? I haven't found anything useful myself: only things where I thought it would be useful, but wasn't. Some things which spring to mind, however, are:

    • Centering a single-line piece of text. I'm thinking buttons and/or titles here. (Although UILabel and UIButton can do it, sometimes you want to draw it yourself.)
    • Calculating the bounds for an "extract" of a longer piece of text. Here I'm thinking about where you might want to show a snippet of a much larger piece of text.
    0 讨论(0)
  • 2020-11-28 23:23

    Here's something I came up with after applying a few principles from PyjamaSam's example:

    AnnotationPin *myAnnotation = (AnnotationPin *)annotation;
    
    self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];
    self.backgroundColor = [UIColor greenColor];
    self.frame = CGRectMake(0,0,30,30);
    imageView = [[UIImageView alloc] initWithImage:myAnnotation.THEIMAGE];
    imageView.frame = CGRectMake(3,3,20,20);
    imageView.layer.masksToBounds = NO;
    [self addSubview:imageView];
    [imageView release];
    
    CGSize titleSize = [myAnnotation.THETEXT sizeWithFont:[UIFont systemFontOfSize:12]];
    CGRect newFrame = self.frame;
    newFrame.size.height = titleSize.height + 12;
    newFrame.size.width = titleSize.width + 32;
    self.frame = newFrame;
    self.layer.borderColor = [UIColor colorWithRed:0 green:.3 blue:0 alpha:1.0f].CGColor;
    self.layer.borderWidth = 3.0;
    
    UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(26,5,newFrame.size.width-32,newFrame.size.height-12)];
    infoLabel.text = myAnnotation.title;
    infoLabel.backgroundColor = [UIColor clearColor];
    infoLabel.textColor = [UIColor blackColor];
    infoLabel.textAlignment = UITextAlignmentCenter;
    infoLabel.font = [UIFont systemFontOfSize:12];
    
    [self addSubview:infoLabel];
    [infoLabel release];
    

    In this example, I'm adding a custom pin to a MKAnnotation class that resizes a UILabel according to the text size. It also adds an image on the left side of the view, so you see some of the code managing the proper spacing to handle the image and padding.

    The key is to use CGSize titleSize = [myAnnotation.THETEXT sizeWithFont:[UIFont systemFontOfSize:12]]; and then redefine the view's dimensions. You can apply this logic to any view, but it doesn't handle linebreaks like Pyjama's.

    Although Pyjama's answer works for some, it didn't work for me. This is a detailed explanation that you should try immediately before going anywhere else if you want a dynamic custom MKAnnotation pin with an image and resizable UILabel.

    0 讨论(0)
  • 2020-11-28 23:31

    It sounds like it would be good for single line labels. For example, if you're drawing a string that may be truncated or have a line break, but you won't actually draw more than one line. It could still be helpful to know the exact height and width of the string, so you can position it exactly where you want it (and draw other UI items around it).

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