UITableView dynamic cell heights only correct after some scrolling

后端 未结 24 1244
误落风尘
误落风尘 2020-11-29 16:41

I have a UITableView with a custom UITableViewCell defined in a storyboard using auto layout. The cell has several multiline UILabels.

相关标签:
24条回答
  • 2020-11-29 17:03

    Setting preferredMaxLayoutWidth helps in my case. I added

    cell.detailLabel.preferredMaxLayoutWidth = cell.frame.width
    

    in my code.

    Also refer to Single line text takes two lines in UILabel and http://openradar.appspot.com/17799811.

    0 讨论(0)
  • 2020-11-29 17:04

    I have a similar problem, at the first load, the row height was not calculated but after some scrolling or go to another screen and i come back to this screen rows are calculated. At the first load my items are loaded from the internet and at the second load my items are loaded first from Core Data and reloaded from internet and i noticed that rows height are calculated at the reload from internet. So i noticed that when tableView.reloadData() is called during segue animation (same problem with push and present segue), row height was not calculated. So i hidden the tableview at the view initialization and put an activity loader to prevent an ugly effect to the user and i call tableView.reloadData after 300ms and now the problem is solved. I think it's a UIKit bug but this workaround make the trick.

    I put theses lines (Swift 3.0) in my item load completion handler

    DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: {
            self.tableView.isHidden = false
            self.loader.stopAnimating()
            self.tableView.reloadData()
        })
    

    This explain why for some people, put a reloadData in layoutSubviews solve the issue

    0 讨论(0)
  • 2020-11-29 17:05

    I had same experience in one of my projects.

    Why it happens?

    Cell designed in Storyboard with some width for some device. For example 400px. For example your label have same width. When it loads from storyboard it have width 400px.

    Here is a problem:

    tableView:heightForRowAtIndexPath: called before cell layout it's subviews.

    So it calculated height for label and cell with width 400px. But you run on device with screen, for example, 320px. And this automatically calculated height is incorrect. Just because cell's layoutSubviews happens only after tableView:heightForRowAtIndexPath: Even if you set preferredMaxLayoutWidth for your label manually in layoutSubviews it not helps.

    My solution:

    1) Subclass UITableView and override dequeueReusableCellWithIdentifier:forIndexPath:. Set cell width equal to table width and force cell's layout.

    - (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell *cell = [super dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
        CGRect cellFrame = cell.frame;
        cellFrame.size.width = self.frame.size.width;
        cell.frame = cellFrame;
        [cell layoutIfNeeded];
        return cell;
    }
    

    2) Subclass UITableViewCell. Set preferredMaxLayoutWidth manually for your labels in layoutSubviews. Also you need manually layout contentView, because it doesn't layout automatically after cell frame change (I don't know why, but it is)

    - (void)layoutSubviews {
        [super layoutSubviews];
        [self.contentView layoutIfNeeded];
        self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width;
    }
    
    0 讨论(0)
  • 2020-11-29 17:06

    I ran into this issue and fixed it by moving my view/label initialization code FROM tableView(willDisplay cell:) TO tableView(cellForRowAt:).

    0 讨论(0)
  • 2020-11-29 17:07
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    
    //  call the method dynamiclabelHeightForText
    }
    

    use the above method which return the height for the row dynamically. And assign the same dynamic height to the the lable you are using.

    -(int)dynamiclabelHeightForText:(NSString *)text :(int)width :(UIFont *)font
    {
    
        CGSize maximumLabelSize = CGSizeMake(width,2500);
    
        CGSize expectedLabelSize = [text sizeWithFont:font
                                    constrainedToSize:maximumLabelSize
                                        lineBreakMode:NSLineBreakByWordWrapping];
    
    
        return expectedLabelSize.height;
    
    
    }
    

    This code helps you finding the dynamic height for text displaying in the label.

    0 讨论(0)
  • 2020-11-29 17:11

    In my case, a stack view in the cell was causing the problem. It's a bug apparently. Once I removed it, the problem was solved.

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