views:

11396

answers:

9
+19  A: 

Resize the frame for the label using the text you want to insert. That way you can accommodate any number of lines.

    CGSize maximumSize = CGSizeMake(300, 9999);
    NSString *dateString = @"The date today is January 1st, 1999";
    UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
    CGSize dateStringSize = [dateString sizeWithFont:dateFont 
        constrainedToSize:maximumSize 
        lineBreakMode:self.dateLabel.lineBreakMode];

    CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);

    self.dateLabel.frame = dateFrame;

This page has some different code for the same solution:

http://discussions.apple.com/thread.jspa?threadID=1759957

nevan
+3  A: 

I took a while to read the code, as well as the code in the introduced page, and found that they all try to modify the frame size of label, so that the default center vertical alignment would not appear.

however, in some cases we do want the label to occupy all those spaces, even if the label does have so much text (e.g. multiple rows with equal height)

here, I used an alternative way to solve it, by simply pad newlines to the end of label (pls note that I actually inherited the UILabel, but it is not necessary):

        CGSize fontSize = [self.text sizeWithFont:self.font];

        finalHeight = fontSize.height * self.numberOfLines;
        finalWidth = size.width;    //expected width of label


        CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


        int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

        for(int i=0; i< newLinesToPad; i++)
        {
            self.text = [self.text stringByAppendingString:@"\n "];
        }
Walty
+6  A: 

Like the answer above, but it wasn't quite right, or easy to slap into code so I cleaned it up a bit. Add this extension either to it's own .h and .m file or just paste right above the implementation you intend to use it:

#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end


@implementation UILabel (VerticalAlign)
- (void)alignTop
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=1; i< newLinesToPad; i++)
    {
        self.text = [self.text stringByAppendingString:@"\n"];
    }
}

- (void)alignBottom
{
    CGSize fontSize = [self.text sizeWithFont:self.font];

    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label


    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];


    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;

    for(int i=1; i< newLinesToPad; i++)
    {
        self.text = [NSString stringWithFormat:@"\n%@",self.text];
    }
}
@end

And then to use, put your text into the label, and then call the appropriate method to align it:

[myLabel alignTop];

or

[myLabel alignBottom];
BadPirate
Your version has some errors that some of the others don't. The loops were supposed to start at i=0 and the blank lines have to include the space.
alltom
Alltom, check the logic in practice. This is the exact code I am using for a couple of apps without any issue :) for a lets say font size 10, 2 line UILabel, with 1 line of text (100px long at 10px high). fontSize = 10, finalHeight = 20, finalWidth = 100, theStringSize.height = 10, therefore newLinesToPad = 20 - 10 / 10 or 2, and my program will add 1 newline.. (to the top or bottom depending) to position properly :)
BadPirate
A: 

You can just use a UITextView with editable = NO. Simple :)

rustyshelf
But you can still select the text that way.
nonamelive
+2  A: 

An even quicker (and dirtier) way to accomplish this is by setting the UILabel's line break mode to "Clip" and adding a fixed amount of newlines.

myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];

This solution won't work for everyone -- in particular, if you still want to show "..." at the end of your string if it exceeds the number of lines you're showing, you'll need to use one of the longer bits of code -- but for a lot of cases this'll get you what you need.

Purple Ninja Girl
+2  A: 

Try this for rotating label myLabel.transform = CGAffineTransformMakeRotation (-3.14/2) //the (-3.14/2) is a 90 degree rotation in radian measure

ganesh
A: 

1) Set the new text:

myLabel.text = @"Some Text"

2) Set the maximum number of lines you want in your label (0 means unlimited):

myLabel.numberOfLines = 0

3) Set the frame of the label to the maximum size:

myLabel.frame = CGRectMake(20,20,200,800)

4) Call sizeToFit to reduce the frame size so the contents just fit:

[myLabel sizeToFit]

The labels frame is now just high and wide enough to fit your text. The top left should be unchanged. I have tested this only with top left aligned text. For other alignments, you might have to modify the frame afterwards.

Also, my label has word wrapping enabled.

Jakob Egger
This works if you want your UILabel to only have one line of text. If you want multiple lines, like I did, this doesn't work as it makes the label one long line.
Ben Clayton
It did work for me, for some reason. I don't know why... maybe sizeToFit depends on autoresizing properties? Or maybe its because I set the maximum number of lines to 0(unlimited)? Or maybe its because I started with a big label, with the entire text fitting and sizeToFit only had to reduce the label size... hmm. I'll have to look into that.
Jakob Egger
Thanks Jakob - let us all know what you find out. If there is a magic set of properties to set it'd save me needing to include Johnun's code in a whole bunch of apps :-)
Ben Clayton
Hey Ben, I just looked at my old code again, and updated my answer with the correct steps necessary.
Jakob Egger
+4  A: 

Refering to the extension solution:

for(int i=1; i< newLinesToPad; i++) 
    self.text = [self.text stringByAppendingString:@"\n"];

should be replaced by

for(int i=0; i<newLinesToPad; i++)
    self.text = [self.text stringByAppendingString:@"\n "];

Additional space is needed in every added newline, because iPhone UILabels' trailing carriage returns seems to be ignored :(

Similarly, alignBottom should be updated too with a @" \n@%" in place of "\n@%" (for cycle initialization must be replaced by "for(int i=0..." too).

The following extension works for me:

// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end

// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [self.text stringByAppendingString:@"\n "];
}

- (void)alignBottom {
    CGSize fontSize = [self.text sizeWithFont:self.font];
    double finalHeight = fontSize.height * self.numberOfLines;
    double finalWidth = self.frame.size.width;    //expected width of label
    CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
    int newLinesToPad = (finalHeight  - theStringSize.height) / fontSize.height;
    for(int i=0; i<newLinesToPad; i++)
        self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end

Then call [yourLabel alignTop]; or [yourLabel alignBottom]; after each yourLabel text assignment.

D.S.
Thanks D.S. That worked perfectly for me! I'd vote you up more than one if I could.
Ben Clayton
A: 

I wanted to have a label which was able to have multi-lines, a minimum font size, and centred both horizontally and vertically in it's parent view. I added my label programmatically to my view:

- (void) customInit {
    // Setup label
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    self.label.numberOfLines = 0;
    self.label.lineBreakMode = UILineBreakModeWordWrap;
    self.label.textAlignment = UITextAlignmentCenter;

    // Add the label as a subview
    self.autoresizesSubviews = YES;
    [self addSubview:self.label];
}

And then when I wanted to change the text of my label...

- (void) updateDisplay:(NSString *)text {
    if (![text isEqualToString:self.label.text]) {
        // Calculate the font size to use (save to label's font)
        CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
        self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
        CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
            self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
            textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
        }
        // In cases where the frame is still too large (when we're exceeding minimum font size),
        // use the views size
        if (textSize.height > self.frame.size.height) {
            textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
        }

        // Draw 
        self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
        self.label.text = text;
    }
    [self setNeedsDisplay];
}

Hope that helps someone!

Johnus