Resize UILabel to fit text inside custom UITableViewCell regardless of width

不问归期 提交于 2019-12-06 04:59:00

问题


I'm trying to get a label in a cell to be the right size, regardless of device or orientation. I am able to get the row height to size correctly. I am also able to set the label height correctly in cellForRowAtIndexPath, and can check that in my logs. But, by the time it gets to willDisplayRowAtIndexPath, the label height has changed, but only when the cell is not 320 pts wide.

Here's my code-

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"CustomCellIdentifier";
CustomInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
    cell = [[CustomInfoCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
    NSArray *objects = [[NSBundle mainBundle] loadNibNamed:@"CustomInfoCell" owner:self options:nil];
    cell = objects[0];
}

// Configure the cell...
cell.customTitleLabel.text = [_data[indexPath.row] objectForKey:t];

CGFloat labelWidth = self.view.frame.size.width-40;
NSLog(@"labelWidth:%f",labelWidth);

NSString *text = [_data[indexPath.row] objectForKey:d];//correct text
CGSize labelsize=[text sizeWithFont:cell.customDetailLabel.font constrainedToSize:CGSizeMake(labelWidth, 2000.0) lineBreakMode:cell.customDetailLabel.lineBreakMode];
NSLog(@"labelsize:%f,%f",labelsize.width,labelsize.height);

//For testing
cell.customDetailLabel.backgroundColor = [UIColor redColor];
NSLog(@"Pre: %@",cell.customDetailLabel);
cell.customDetailLabel.frame=CGRectMake(20, 22, labelWidth, labelsize.height);

cell.customDetailLabel.text = text;
    NSLog(@"Post: %@",cell.customDetailLabel);
return cell;
}

In willDisplayRowAtIndexPath I also print the label info. Here's what one row prints-

2013-03-24 18:33:44.009 Bridge Alert[57793:1e503] labelWidth:728.000000
2013-03-24 18:33:44.010 Bridge Alert[57793:1e503] labelsize:713.000000,76.000000
2013-03-24 18:33:44.010 Bridge Alert[57793:1e503] Pre: <UILabel: 0xad3eaf0; frame = (20 20; 280 21); text = 'Detail'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x17372eb0>>
2013-03-24 18:33:44.011 Bridge Alert[57793:1e503] Post: <UILabel: 0xad3eaf0; frame = (20 22; 728 76); text = 'Detail'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x17372eb0>>
2013-03-24 18:33:44.011 Bridge Alert[57793:1e503] Text set: <UILabel: 0xad3eaf0; frame = (20 22; 728 76); text = 'A bridge is considered “f...'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x17372eb0>>
2013-03-24 18:33:44.014 Bridge Alert[57793:1e503] Display:<UILabel: 0xad3eaf0; frame = (20 20; 728 190); text = 'A bridge is considered “f...'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x17372eb0>>

As you can see, by Display, the label is resized. I'm assuming the height is recalculated somehow, based on if the cell were 320 pt wide, which is the built in UITableViewCell width.

How can I get the label to size correctly?


回答1:


Have you tried unchecking auto layout? This will remove the unnecessary (mostly unhelpful) Constraints.




回答2:


This is what worked for me with the minimal code as possible using AutoLayout.

Within my ViewController I added the following methods

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{        
    NSString * yourText = //place here the text you want to calculate its size;
    return 40 + [self heightForText:yourText];
}

-(CGFloat)heightForText:(NSString *)text
{
    NSInteger MAX_HEIGHT = 2000;
    UITextView * textView = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, 320, MAX_HEIGHT)];
    textView.text = text;
    textView.font = [UIFont boldSystemFontOfSize:12];
    [textView sizeToFit];
    return textView.frame.size.height;
}

This code above basically changes UITableViewCell's size based on the size of my UILabel + a padding number which in my case I defined as 40.

After this I had to add a couple of constraints as shown below in order to make the UILabel to "stretch" as UITableViewCell does

After running it:

Note: I took different pieces of code from many threads in SO to come up with this solution. I wish I could remember all of `em to mention here

Hope it works for you guys.

Cheers




回答3:


In my opinion, interface builder/storyboard can be useful but often adds another unneeded layer of complexity. I would simply subclass UITableViewCell (as you are but do it purely programmatically) and set the frame of customDetailLabel using the layoutSubviews.




回答4:


I used to have the exact same problem, for some reason the label height changes when it actually gets displayed. I ended up using the free Sensible TableView framework, which actually manages to do the resizing correctly (it even resizes the cell if you choose to have a multiline UILabel). The framework also assigned the label's text automatically from my object's property which was really cool.




回答5:


Try overriding setFrame in your CustomInfoCell class to include resizing the elements in your cell after you set the frame. I've included code I use to accomplish this, which is a little different from your implementation. Also, on your label I set the autoresizing mask to UIViewAutoresizingFlexibleWidth.

Have this at the top of your file:

static void *kKVOContext;   // See: http://www.dribin.org/dave/blog/archives/2008/09/24/proper_kvo_usage/

In viewDidLoad include:

[self.textLabel addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:&kKVOContext];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
               selector:@selector(orientationChanged:)
                   name:UIDeviceOrientationDidChangeNotification
                 object:[UIDevice currentDevice]];

Then include:

- (void)setFrame:(CGRect)frame
{
    [super setFrame:frame];

    //Resize elements to fit inside new frame
    [self textChanged];
}

- (CGSize)textLabelSize
{
    BOOL portrait = UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation);
    CGFloat width = portrait ? [UIScreen mainScreen].bounds.size.width : [UIScreen mainScreen].bounds.size.height;
    CGFloat maxWidth = width - 90 - TEXT_X_LEFT_PADDING;
    CGSize maximumLabelSize = CGSizeMake(maxWidth, 10000);

    return [self.textLabel.text sizeWithFont:self.textLabel.font
                                               constrainedToSize:maximumLabelSize
                                                   lineBreakMode:self.textLabel.lineBreakMode];
}
- (CGFloat)cellHeight
{
    CGSize expectedLabelSize = [self textLabelSize];

    return (self.titleLabel.frame.origin.y+self.titleLabel.frame.size.height) + expectedLabelSize.height;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

    if ([keyPath isEqual:@"text"] && object == self.textLabel) {
        [self textChanged];
    }

    if(context != &kKVOContext)
    {
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
    }
}

- (void)orientationChanged:(NSNotification *)note
{
    //Resize text on orientation change
    [self textChanged];
}

- (void)textChanged
{
    CGRect newFrame = self.textLabel.frame;
    newFrame.size = [self textLabelSize];

    if(!CGRectEqualToRect(self.textLabel.frame, newFrame))
    {
        self.textLabel.frame = newFrame;
    }
}



回答6:


Just post my own simplified approach based on @Paulo, but now with adapt to storyboard constraints width and more accurate.

(Swift)

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier")!

    // Use subclass of UITableViewCell if your cell is complex.
    let label = cell.viewWithTag(3001) as! UILabel;
    label.text = someStringArray[indexPath.row]
    label.sizeToFit();

    let y = label.frame.origin.y
    let height = label.frame.size.height
    let paddingBottom: CGFloat = 8
    // add other controls/view height if any after the expand label

    return y + height + paddingBottom
}


来源:https://stackoverflow.com/questions/15605853/resize-uilabel-to-fit-text-inside-custom-uitableviewcell-regardless-of-width

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!