Is there a way to combine static tableview cells (static content) with dynamic tableview cells (prototype content) using storyboard?
8 Answers
I suggest you treat your table as dynamic, but include the cells you always want at the top. In the Storyboard, place a UITableViewController
and have it use a dynamic table. Add as many UITableViewCell
prototypes to the table as you need. Say, one each for your static cells, and one to represent the variable cells.
In your UITableViewDataSource
class:
#define NUMBER_OF_STATIC_CELLS 3
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dynamicModel count] + NUMBER_OF_STATIC_CELLS;
}
and, then
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row < NUMBER_OF_STATIC_CELLS) {
// dequeue and configure my static cell for indexPath.row
NSString *cellIdentifier = ... // id for one of my static cells
} else {
// normal dynamic logic here
NSString *cellIdentifier = @"DynamicCellID"
// dequeue and configure for [self.myDynamicModel objectAtIndex:indexPath.row]
}
}
-
This is what I did a year ago and I guess this is still the only viable solution. I was hoping for something more elegant but oh well. Thanks for the info. – tazboy Mar 22 '12 at 00:52
-
1In the storyboard, do I have to set the "Content" as "Static Cells" or "Dynamic Cells"? – Satyam Sep 30 '13 at 06:59
-
Dynamic. It's really just dynamic with the datasource providing some cells based on a fixed model and others based on a dynamic model. – danh Sep 30 '13 at 16:43
-
There is a huge drawback, that you have to convert your indexPath in all protocols to deal with dynamic cells. Afaik, this is the only way to do what you want – Nikita Took Jan 22 '14 at 11:38
-
2Much of the unhappiness can be avoided if you devote distinct sections to the fixed length and to the dynamic rows. The UI can stay the same between these, using no headers same cell types, etc. – danh Jan 22 '14 at 15:21
-
With Static table view we can make references of Component inside cell in view controller. How can should I achieve same with dynamic table View. – rptwsthi Oct 29 '14 at 12:46
-
In dynamic table, don't keep a ref to a cell's subview or a cell. Keep model data around that describes the subview (e.g. a string for a UILabel). Then update that view in the datasource (cellForRowAtIndexPath). – danh Oct 29 '14 at 14:16
I had a problem, although it was a slight variant of this. I actually wanted to mix dynamic and static cells but in different groups. Meaning group 1 would have static only cells and group 2 would have dynamic cells.
I accomplished this by actually hard coding static cell values (based on their prototype cell identifiers). The dynamic sections would have normal dynamically populated content. Here is some example code in case anyone else has the same issue:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == 1){
return @"Dynamic Cells";
}
if (section == 0){
return @"Static Cells";
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 0) {
return 1; //However many static cells you want
} else {
return [_yourArray count];
}
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
if (indexPath.section == 0) {
NSString *cellIdentifier = @"staticCellType";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = @"some static content";
return cell;
} else if (indexPath.section == 1){
NSString *cellIdentifier = @"dynamicCellType";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [_yourArray objectAtIndex:indexPath.row];
return cell;
}
return nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}

- 1,236
- 14
- 20
-
2This is better then the answer above. Static and dynamic contents can be in different section.Thanks. – Mavlarn Jan 19 '13 at 09:27
-
This is technically all dynamic content. You're still dynamically returning the static content even if it's not strictly changing. "Static" in the `UITableView` sense refers to tables that have been laid-out using Interface Builder. There is indeed a way to mix static and dynamic content, though. You have to override a bunch of UITableViewDataSource methods to do it. – devios1 Aug 06 '13 at 21:47
-
Perfect solution. Thank you very much. By the way, you dont even need create the view/controller/cell on interface builder this way. You can just do it by code. Thanks! – Gutemberg Ribeiro Oct 31 '13 at 04:26
-
-
Wonderful solution for people who requires only one or two rows of cells to be static, encapsulating UILabel, UIButton, etc. This keeps a clear separation for dynamic cells in its intended operations. – Keith OYS May 22 '14 at 07:44
Since no one has actually provided a real answer to the problem (using both static and prototype cells in the same table view), I figured I'd chime in. It can be done!
Create your static cells as you see fit. For the sections that need a dynamic cell, if you are NOT using standard UITableViewCell type, you'll need to create your custom one in a separate Nib, otherwise you can use the standard ones. Then implement the following delegates. Basically for each of these delegates, for the static stuff we want to call super, for the dynamic, we return our values.
First, IF you need to selectively show your dynamic section, you'll want to implement the numberOfSectionsInTableView (otherwise you can leave this delegate out):
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
int staticSections = 1;
int dynamicSections = 1;
if (SOME_BOOLEAN) {
return staticSections + dynamicSections;
} else {
return staticSections;
}
}
Then, you need to implement numberOfRowsInSection:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 1) {
return A_COUNT;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
Then, you need to implement heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return 44.0f;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
Then indentationLevelForRowAtIndexPath:
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
return 1; // or manually set in IB (Storyboard)
} else {
return [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath]; // or 0
}
}
Finally, cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1) {
SomeObject *obj = self.someArray[indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"DynamicCell" forIndexPath:indexPath];
cell.textLabel.text = obj.textValue;
return cell;
} else {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
Unfortunately, this is not possible since static table views must be in a UITableViewController and that only allows one tableview.
What you need to do is make three more dynamic UITableviewCell's and load them individually for the first three rows where you want the static content.
If you aren't sure how to do this, let me know and I can find some code.

- 25,760
- 8
- 60
- 101
-
1This is right, and you're not losing much. You would need to manually return the static cells from tableView:cellForIndexPath: anyway, so you'll just need to do it using the cell identifier instead of making an IBOutlet/property connection. The biggest loss is that you won't be able to tie individual text fields to properties automatically, but if you tag everything you should be able to do this in viewDidLoad. – Nate Cook Mar 21 '12 at 21:52
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.

- 1,241
- 1
- 13
- 25
You can't have one tableview be static and the other dynamic in the same view controller so you will need to make them both dynamic. In the first tableview you will configure the cells in code on initializing the view controller never update them.
- Add a UIViewController to your storyboard.
- Add two Table Views (Not TableViewControllers) to the UIView Controller.
- Select each tableView and configure both for dynamic cells.
- Build and attach your view controller. 2 tableview on a single view explains that step.
As another option you can achieve a similar look by embedding your dynamic tableview in part of a view similar to the link in step 4 and then do whatever you wanted to in the rest of the view to setup what you were planning to do with static cells by using scrollviews, labels, and buttons.
-
Unfortunately, that is not possible. I need three static cells and then dynamic cells below that could hold anywhere from 12-33 persons. I made it in code before but I'm really enjoying storyboard and was hoping I could accomplish the same there. – tazboy Feb 17 '12 at 21:30
-
For whatever reason I didn't think of trying that. Thanks. I'll look more into using two view controllers for the two tables. Seems to make sense. – tazboy Feb 21 '12 at 01:47
-
I don't believe this is a possibility. It allows me to compile and run the app but it doesn't show the static content. I get this error, "Static table views are only valid when embedded in UITableViewController instances". Turns out that UITableViewControllers provide some magic to static content. – tazboy Feb 21 '12 at 02:09
-
I investigated further and got the same error as you did. I see that you could have two different dynamic table views as show in the link on step 5, but Xcode won't allow you to make one of them static cells. I can figure a way around it. You might be able to achieve a similar look by embedding your dynamic tableview in part of a view similar to the link in step 5 and then do whatever you wanted to in the rest of the view with scrollviews, labels, and buttons. – T.J. Feb 21 '12 at 04:02
-
You could also create buttons (one for each static cell you have) that are styled like your cells and place them in the tableHeaderView or tableFooterView of the UITableView; those buttons are just views after all.
You'll need to add some logic for making selections on the buttons vs. the cells so it maintains the usual look and feel.
Of course, this assumes that you want to insert static cells into your table view at the top or bottom of the table.
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;
}

- 3,148
- 2
- 23
- 31