Table View Cell AutoLayout in iOS8

血红的双手。 提交于 2019-12-21 19:42:29

问题


I can't seem to get AutoLayout working on my Table View Cells.

On some cells it seems to work, and on others it seems to not work. Even cells of the exact same kind.

For example, on some cells the Description will be more than 1 lines worth of text and it will work correctly...

...Yet on other cells the Description will be more than 1 lines worth of text but only show 1 line of it with a bunch of empty space.

Can you help me figure out what I'm missing or doing wrong? Thanks!

I'm using this StackOverflow question to guide my process as a first-timer doing this: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

1. Set Up & Add Constraints

These are working well for the most part I believe.

2. Determine Unique Table View Cell Reuse Identifiers

I'm not totally sure if I need to worry about this part since I will always have a Headline, Time, and Description.

For iOS 8 - Self-Sizing Cells 3. Enable Row Height Estimation

I added this to viewDidLoad:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 180.0;

UPDATE: Adding more info per Acey request

To be clear, I put constraints:

  • Headline: 15 left, 85 top, 15 right
  • Vertical Spacing between Headline and Time, of 10
  • Vertical Spacing between Time and Description, of 10
  • I Cmd clicked all three labels and added Leading Edges and Trailing Edges
  • I pinned 20 between Description and the bottom of the Table View Cell

UPDATE 2: Solved Answer below worked really well, but also any extra spacing was due to height set for cell being too large, so Xcode was automatically adding extra space to fill out height of cell since text labels didn't fill out the full height of the Table View Cell.

Let me know if you have any questions or need any help on this if you come across this and have the same problem.

Thanks everyone!


回答1:


I haven't tried using the new iOS 8 mechanisms yet. But I have faced similar issues when I was doing this with iOS 6 / 7. After updating the app to iOS 8 it still works fine, so maybe the old way is still the best way?

I have some examples of my code here: AutoLayout multiline UILabel cutting off some text

And here: AutoLayout uitableviewcell in landscape and on iPad calculating height based on portrait iPhone

Long story short the pre iOS 8 way involved keeping a copy of a cell just for calculating the height inside tableView:heightForRowAtIndexPath:. But this wasn't enough for dealing with multi line UILabel's. I had to subclass UILabel to update the preferredMaxLayoutWidth every time layoutSubviews was called.

The preferredMaxLayoutWidth "fix" seemed to be the magic secret I was missing. Once I did this most of my cells worked perfectly.

The second issue I had only required me to set the content compression resistance and content hugging properties correctly, so for example telling the label to hug the text will mean it won't expand to fill the whitespace which will cause the cell to shrink.

Once I did these 2 things my cells now handle any font size, or any amount of text without any messy layout code. It was a lot to learn but I do think it paid off in the end, as I have a lot of dynamic content in my app.

Edit

After coming across a few issues of my own with iOS 8, i'm adding some more details to solve these very odd autoLayout bugs.

With the code I mentioned, it doesn't seem to work when the cell "Row Height" is not set to custom. This setting is found in IB by selecting the cell and clicking the autoLayout tab (where all the content compression resistance settings etc are). Press the checkbox and it will fill with a temporary height.

Second is, in my code I keep a local copy of a cell, and then reuse it many times inside the heightForRowAtIndexPath: method. This seems to increase the cell height by a lot every time it is called. I had to re-init the local copy by calling:

localCopy = [self.tableView dequeueReusableCellWithIdentifier:@"mycell"];

It appears the new Xcode 6 / iOS 8 changes are very much so not backwards compatible with iOS 7 and it seems to be managed quite differently.

Hope this helps.

Edit 2

after reading this question: iOS AutoLayout multi-line UILabel

I've come across another issue with iOS 7 / iOS 8 autolayout support!!! I was overriding layoutSubviews for iOS 8 I also needed to override setBounds to update the preferredMaxLayoutWidth after calling super. WTF have apple changed!

Seems to be an issue with the setting in IB for preferredMaxLayoutWidth, because iOS 7 can't use the automatic feature, if you use the same UILabel on multiple devices, its only going to use the 1 width. So UITableViewCell's on an iOS 8 tablet will be bigger because the same cell needs to have 2 lines on an iOS 8 iPhone.




回答2:


Here is my attempt.

You could create a method/function that get's you the cellview that you need. Like so:

- (UIView *) getCellView {

    UIView *cellView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 0.0f)];
    cellView.tag = 1;
    cellView.backgroundColor = [UIColor clearColor];

    UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(15.0f, 10.0f, 15.0f, 15.0f)]; //I assumed that was the size of your imageView;
    imgView.image = [UIImage imageNamed:@"whatever-your-image-is-called"];
    [cellView addSubview:imgView];

    CGFloat xPadding = 15.0f;
    CGFloat yPadding = 15.0f;
    UILabel *headlineLabel = [[UILabel alloc ]initWithFrame:CGRectMake(xPadding, 0.0f, self.view.frame.size.width - (xPadding*2), 0.0f)];
    headlineLabel.numberOfLines = 0;
    headlineLabel.text = @"Red Sox season fell apart after World Series title (The Associated Press)";
    [headlineLabel sizeToFit];
    CGRect hFrame = headlineLabel.frame;
    if(hFrame.size.width > self.view.frame.size.width - 31.0f)
        hFrame.size.width = self.view.frame.size.width - 30.0f;
    hFrame.origin.y = imgView.frame.size.height + yPadding;
    headlineLabel.frame = hFrame;

    UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(xPadding, 0.0f, self.view.frame.size.height-(xPadding*2), 0.0f)];
    timeLabel.text = @"4h";
    //timeLabel.numberOfLines = 0; //uncomment if it will wrap on multiple lines;
    [timeLabel sizeToFit];
    hFrame = timeLabel.frame;
    if(hFrame.size.width > self.view.frame.size.width - 31.0f)
        hFrame.size.width = self.view.frame.size.width - 30.0f;
    hFrame.origin.y = headlineLabel.frame.size.height + yPadding;
    timeLabel.frame = hFrame;

    UILabel *descriptLabel = [[UILabel alloc] initWithFrame:CGRectMake(xPadding, 0.0f, self.view.frame.size.height - (xPadding*2), 0.0f)];
    descriptLabel.text = @"Boston (AP) -- To Boston Red Sox manager John Farrel, it hardly seems possible that just 11 months ago his team was celebrating the World Series championship on the field at Fenway Park.";
    descriptLabel.numberOfLines = 0; //I would suggest something like 4 or 5 if the description string vary from 1 line to more than 5 lines.
    [descriptLabel sizeToFit];
    hFrame = descriptLabel.frame;
    if(hFrame.size.width > self.view.frame.size.width - 31.0f)
        hFrame.size.width = self.view.frame.size.width - 30.0f;
    hFrame.origin.y = timeLabel.frame.size.height + yPadding;
    descriptLabel.frame = hFrame;

    cellView.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.width, descriptLabel.frame.origin.y + descriptLabel.frame.size.height + 15.0f /*some padding*/);
    return cellView;
}

If you are using indexPath.row, you could just change the method name to be - (UIView *)getCellView:(NSIndex) *indexPath and it should work the same.

Then in your heightForRowAtIndexPath you could do

return [[self getCellView] frame].size.height;

or

return [[self getCellView:indexPath] frame].size.height

And in your cellForRowAtIndexPath you could just do the following

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {

    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.textLabel.text = @"";
    cell.detailTextLabel.text = @"";
}
[[cell viewWithTag:1] removeFromSuperview];
[cell addSubview:[self getCellView]; //or [cell addSubview:[self getCellView:indexPath]];
return cell;

Hope this helps. Let me know if something was unclear or not quite working. There are some stuff you may need to tweak to fit your usage, especially in cellForRowAtIndexPath, but that should be more or less everything you need to get going. Happy coding.



来源:https://stackoverflow.com/questions/26110703/table-view-cell-autolayout-in-ios8

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