Is there a way to combine static tableview cells (static content) with dynamic tableview cells (prototype content) using storyboard?
You can always make one you your tableviews appear similar to the static table but define it in code. Set the sections, amount or rows per section, headers etc. through the delegate methods.
One way to have dynamic content in a static table view is to clone cells where additional rows are needed.
For the dynamic section of my table view, I lay out one or more cells in Interface Builder. At runtime, I can clone those by archiving using NSCoder and then unarchiving.
It works, but is not necessarily prettier than starting with a dynamic prototype table view and creating static rows from there.
It fails with standard table view cells. The lazily created text labels are not laid out correctly. Hence I used UITableViewCell subclasses where I take care of archiving and unarchiving subviews.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == kContactsSection) {
NSArray *contacts = self.contacts;
Contact *contact = [contacts objectAtIndex:indexPath.row];
NSString *name = contact.name;
NSString *role = contact.role;
if ([role length] == 0) {
NNContactDefaultTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier : @"contactDefault"];
if (cell == nil) {
NNContactDefaultTableViewCell *template = (id)[super tableView : tableView
cellForRowAtIndexPath :[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:template];
cell = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
cell.contactTextLabel.text = name;
return cell;
}
else {
NNContactDetailTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier : @"contactDetail"];
if (cell == nil) {
NNContactDetailTableViewCell *template = (id)[super tableView : tableView
cellForRowAtIndexPath :[NSIndexPath indexPathForRow:1 inSection:kContactsSection]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:template];
cell = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
cell.contactTextLabel.text = name;
cell.contactDetailTextLabel.text = role;
return cell;
}
}
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
In the above example I have two cell types. Both laid out in Interface Builder as part of a static table view.
To get dynamic content in one section, I also need to override the following methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == kContactsSection) {
NSArray *contacts = self.contacts;
NSUInteger contactCount = [contacts count];
return contactCount;
}
return [super tableView:tableView numberOfRowsInSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger section = indexPath.section;
NSInteger row = indexPath.row;
if (section == kContactsSection) {
return [super tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
}
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger section = indexPath.section;
if (section == kContactsSection) {
CGFloat indentation = [super tableView:tableView indentationLevelForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:kContactsSection]];
return indentation;
}
CGFloat indentation = [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
return indentation;
}