I have grouped UITableView.
Here is my header views method - NOTE I made it so it loads only once and next time rather than reloading elements it just returns headerView if it has subviews in it already (I need that cause I have elements in headerView that change state and I do not want them to reload):
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
static NSString *headerReuseIdentifier = @"myHeader";
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
if (headerView == nil) {
headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:headerReuseIdentifier];//[tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
CGRect frame=CGRectMake(0, 0, tableView.bounds.size.width, 44);
headerView.frame=frame;
}
if (headerView.contentView.subviews.count!=0){
return headerView;//do not reload
}
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, tableView.frame.size.width-85, 44)];
[label setFont:[UIFont boldSystemFontOfSize:16]];
NSString *name=@"not found";
[label setText:name];
headerView.backgroundColor=[UIColor clearColor];
[headerView.contentView addSubview:label];
//... etc elements
return headerView;
}
I implemented similar logic for cells too, i.e. they do not reload elements if subviews already added to the cell, just to see how it works there too:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (cell.contentView.subviews.count!=0) {
return cell;//do not reload
}
//adding elements here...
return cell;
}
=====================================================================
here how it looks the 1st time, NOTE Step:1 and Step:2 in correct ascending order
Now, the problem, when [myTableView reloadData] is called the table looks like this:
NOTE: the headerView views are backwards! However, cells always show up in the right order.
If [myTableView reloadData] is called again - the headerViews will show up in proper order.
I can stop this from happening by avoiding calling reloadData, but I need to reload data in the cells and not in the headerViews.
Had anybody experienced this headerViews flipping - how did you fix it?
Xcode 8.3.2, running on iPad iOS9.0 simulator
FULL Code that lets you test this wrong head views reordering:
.h file
@interface TableTestViewController : UIViewController
@property(strong,nonatomic)IBOutlet UITableView *myTable;
@property(strong,nonatomic)NSMutableArray *steps;
@end
.m file
#import "TableTestViewController.h"
@interface TableTestViewController ()
@end
@implementation TableTestViewController
@synthesize steps,myTable;
- (void)viewDidLoad {
[super viewDidLoad];
steps=[[NSMutableArray alloc]initWithObjects:@"Step 1",@"Step 2", nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return steps.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 44.0;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
static NSString *headerReuseIdentifier = @"myHeader";
UITableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
if (headerView == nil) {
headerView = [[UITableViewHeaderFooterView alloc] initWithReuseIdentifier:headerReuseIdentifier];//[tableView dequeueReusableHeaderFooterViewWithIdentifier:headerReuseIdentifier];
CGRect frame=CGRectMake(0, 0, tableView.bounds.size.width, 44);
headerView.frame=frame;
}
if (headerView.contentView.subviews.count!=0) {
return headerView;//do not reload when running
}
while (headerView.contentView.subviews.count) {
id subview=[headerView.contentView.subviews objectAtIndex:0];
[subview removeFromSuperview];
}
headerView.backgroundColor=[UIColor clearColor];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, tableView.frame.size.width-85, 44)];
[label setFont:[UIFont boldSystemFontOfSize:16]];
[label setText:[steps objectAtIndex:section]];
[headerView.contentView addSubview:label];
int btnSz=tableView.bounds.size.width/6;
UIButton *startStepBtn = [[UIButton alloc]initWithFrame:CGRectMake(btnSz*5+5 ,5, 30, 30)];
[startStepBtn setTitle:@"" forState:UIControlStateNormal];
startStepBtn.tag=section+1000;
startStepBtn.enabled=NO;
[startStepBtn addTarget:self action:@selector(startStep:) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside];
[headerView.contentView addSubview:startStepBtn];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
int i=1;
return 60*ceil((double)i/5)+10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if ([cell.contentView.subviews count]!=0) {
return cell;//do not reload when running
}
//clear 1st
while( [cell.contentView.subviews count] ){
id subview = [cell.contentView.subviews objectAtIndex:0];
[subview removeFromSuperview];
}
int btnSz=tableView.bounds.size.width/6;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, tableView.frame.size.width-85, 44)];
[label setFont:[UIFont boldSystemFontOfSize:16]];
[label setText:[steps objectAtIndex:indexPath.section]];
[cell.contentView addSubview:label];
CGRect frame;
frame = CGRectMake(btnSz*5+5 ,5, 30, 30);
UIButton *delStepBtn = [[UIButton alloc]initWithFrame:frame];
[delStepBtn setTitle:@"❌" forState:UIControlStateNormal];
[delStepBtn addTarget:self action:@selector(deleteStep:) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside];
[cell.contentView addSubview:delStepBtn];
frame = CGRectMake(btnSz*5+5 ,5+30, 30, 30);
UIButton *editStepBtn = [[UIButton alloc]initWithFrame:frame];
[editStepBtn setTitle:@"" forState:UIControlStateNormal];
[editStepBtn addTarget:self action:@selector(editStep:) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside];
[cell.contentView addSubview:editStepBtn];
return cell;
}
-(void)editStep:(id)sender{
[myTable reloadData];
}
@end
implement, you will see headers in ascending order, touching the hammer button makes table to reload and headers will be now in descending order, touch again and they are back to ascending order.
However cells content always stays as it is supposed to be in ascending order.