问题
I have a table view form created using Static Cells in IB/Storyboard. However, I need to hide some of the cells at runtime depending on certain conditions.
I have found a few 'answers; to this question on SO, e.g.
UITableView set to static cells. Is it possible to hide some of the cells programmatically?
.. and they focus on setting the height of the cell / row to 0. This is great, except I now get exceptions from AutoLayout because the constraints can't be satisfied. How do I get around this last problem? Can I temporarily disable Auto-Layout for a subview? Is there a better way to be doing this in iOS7?
回答1:
I found the best way to do this is to simply handle the numberOfRowsInSection, cellForRowAtIndexPath and heightForRowAtIndexPath to selectively drop certain rows. Here's a 'hardcoded' example for my scenario, you could do something a little smarter to intelligently remove certain cells rather than hard code it like this, but this was easiest for my simple scenario.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (indexPath.section == 0 && hideStuff) {
cell = self.cellIWantToShow;
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];
if (indexPath.section == 0 && hideStuff) {
height = [super tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
}
return height;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger count = [super tableView:tableView numberOfRowsInSection:section];
if (section == 0 && hideStuff) {
count -= hiddenCells.count;
}
return count;
}
回答2:
Hide the cells on the storyboard and set the height to 0:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let cell: UITableViewCell = super.tableView(tableView, cellForRowAtIndexPath:indexPath)
return cell.hidden ? 0 : super.tableView(tableView, heightForRowAtIndexPath:indexPath)
}
}
回答3:
If you ensure there's no constraint touching the bottom edge of the cell, autolayout shouldn't barf (tested on iOS 6.0, 6.1, 7.0). You'll still 'anchor' to the top edge and have to pin the heights. (You can do the reverse and anchor to the bottom, of course.)
If your layout depends on both the top and bottom edge positions, it may be possible to programmatically remove the constraints (they're just objects, after all).
回答4:
The simplest way is to change height of sections and rows. It works for me.
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == 3) {
return 0;
} else {
return [super tableView:tableView heightForHeaderInSection:section];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (indexPath.section == 3) {
cell.hidden = YES;
return 0;
} else {
cell.hidden = NO;
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
回答5:
The kosher way to do this is to use dynamic cells, setting the row height to 0 is a hack. Static cells are very convenient but limited in functionality.
回答6:
I managed to avoid exceptions from Auto Layout by first removing the constraints on the cell's contentView
programmatically in viewDidLoad
, and then setting that cell's height to 0 in heightForRowAtIndexPath
.
回答7:
I have found a way that allows you even row animations and is working on iOS 8.3. All you need is to implement the tableView:numberOfRowsInSection: data source method and then add/delete row by UITableView methods insertRowsAtIndexPaths:withRowAnimation: and deleteRowsAtIndexPaths:withRowAnimation:.
Here is example of hiding exact row based on UISwitch state:
- (IBAction)alowNotif:(id)sender {
UISwitch *sw = (UISwitch*)sender;
NSIndexPath *index = [NSIndexPath indexPathForRow:5 inSection:0];
if ([sw isOn]) {
[self.tableView insertRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationAutomatic];
}
else {
[self.tableView deleteRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (![notifications isOn]) {
return 5;
}
return 6;
}
As was mentioned above by @algal, numberOfRowInSection: is still UITableViewDataSource method, so one does not simply know how long its gonna work.
回答8:
The best way for me was to modify numberOfRowsInSection method. I removed datasource which i did not want to display. Best solution for me, because everything is in one function.
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(section==0) {
NSUInteger productCount = _products.count;
for(loop trough your data) {
if(your condition is true)
productCount--;
}
}
return productCount;
} else
return self.groups.count;
}
回答9:
Implemented this too, for a tableview in a StoryBoard. My cells are embedded in sections with a header, represented by that blue cube in xcode6 IB. Indeed if you implement heightForHeaderInSection, heightForFooterInSection and titleForHeaderInSection,titleForFooterInSection you can access the headers when the table is displayed, and return 0.0 and nil respectively, and return 0 for numberOfRowsInSection.
Basically it all works fine, except that for every cell hidden a ca. 10 pixel high vertical space remains for every cell (section) you hide. Any idea what that could be?
来源:https://stackoverflow.com/questions/18939879/hide-cells-in-a-uitableview-with-static-cells-and-no-autolayout-crash