Mixing static and dynamic sections in a grouped table view
Dynamic prototype cells can behave like static ones if you just return the cell without adding any content in cellForRowAtIndexPath, so you can have both "static like" cells and dynamic ones (where the number of rows and the content are variable) by using dynamic prototypes.
In the example below, I started with a table view controller in IB (with a grouped table view), and changed the number of dynamic prototype cells to 3. I adjusted the size of the first cell to 80, and added a UIImageView and two labels. The middle cell is a Basic style cell, and the last one is another custom cell with a single centered label. I gave them each their own identifier. This is what it looks like in IB:
Then in code, I did this:
- (void)viewDidLoad {
[super viewDidLoad];
self.theData = @[@"One",@"Two",@"Three",@"Four",@"Five"];
[self.tableView reloadData];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 1)
return self.theData.count;
return 1;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0)
return 80;
return 44;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
if (indexPath.section == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:@"TitleCell" forIndexPath:indexPath];
}else if (indexPath.section == 1) {
cell = [tableView dequeueReusableCellWithIdentifier:@"DataCell" forIndexPath:indexPath];
cell.textLabel.text = self.theData[indexPath.row];
}else if (indexPath.section == 2) {
cell = [tableView dequeueReusableCellWithIdentifier:@"ButtonCell" forIndexPath:indexPath];
}
return cell;
}
As you can see, for the "static like" cells, I just return the cell with the correct identifier, and I get exactly what I set up in IB. The result at runtime will look like your posted image with three sections.
How to have, in a grouped style, two contents : dynamic and static
Put the button in a tableFooterView.
https://github.com/dpfannenstiel/symmetrical-octo-journey
UITableView Mix of Static and Dynamic sections Cells ? throw error -[__NSSingleObjectArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
index 1 beyond bounds [0 .. 0]
suggests something is trying to read users
before it has been populated, so it's still in the initial empty state:
var users = [User]()
The only time you try to index users
is when configuring a cell in your "Dynamic" section, which suggests you've misinformed the tableview about how much data you've got. Also, I don't see any code to report 2
as the number of sections.
Observation: Deferring to super
for any UITableViewDelegate
methods seems odd. How would it be in a better position than your own code to know what cell to provide or how many rows are in a section?
Also, consider using the tableView.dequeueReusableCell(withIdentifier: String, for: IndexPath)
variant as it always returns a cell.
UITableView Mix of Static and Dynamic Cells?
As you stated you can't mix static and dynamic cells. However, what you can do is break up the content into different data arrays that correspond to each group. Then break the table up into difference sections and load the data from the correct array in cellForRowAtIndexPath:.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = @"CELLID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
switch (indexPath.section) {
case 0:{
cell.textLabel.text = self.arrayOfStaticThings1[indexPath.row];
}break;
case 1:{
cell.textLabel.text = self.arrayOfDynamicThings[indexPath.row];
}break;
case 2:{
cell.textLabel.text = self.arrayOfStaticThings2[indexPath.row];
}break;
default:
break;
}
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case 0:{
return self.arrayOfStaticThings1.count;
}break;
case 1:{
return self.arrayOfDynamicThings.count;
}break;
case 2:{
return self.arrayOfStaticThings2.count;
}break;
default:
return 0;
break;
}
}
UITableView dynamic grouped cells
Here is the code TableViewDemo You basically have to use below two methods.
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 4
}
and this for title of header -
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "your title" // Use the titleForHeaderInSection index
}
UITableView: Handle cell selection in a mixed cell table view static and dynamic cells
For static cells you need to call super method. I presume that you will be extending UITableViewController. See below
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell;
/* Detect cell is static or dynamic(prototype) based on the index path and your settings */
if ("Cell is prototype")
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
else if ("Cell is static")
cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
// Modify cell properties if you want
return cell;
}
Also for more information on mixing cells see Mixing static and dynamic table view content discussion on apple forums.
[EDIT]
If you haven't read apple link above then please do so carefully. For dynamic content you will build the cell first time with the given identifier in the code itself. Next time on wards you will dequeue the cell rather than building it! It's the same old way.
Moreover, remember that the static data source thinks there are only 2 sections(for example). You can't ask it about section 2, because it thinks there are only sections 0 and 1. If you're going to be inserting dynamic content anywhere but the end of the table, you need to lie to super when you forward the data source methods. Your numberOfRowsInSection: method, for example, should look something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == 1) {
return 1;
}
else if (section > 1){
section--; // Basically you are forming sections for dynamic content
}
return [super tableView:tableView numberOfRowsInSection:section];
}
The key is making the adjustment for your dynamic content so that the static data source still gets the values it expects
[EDIT]
Here is the complete working example and tested. Just copy past all of following methods in your code and it should work straight way. You have to override all the tableview methods when you have mixed cells. Return the total number of static and dynamic sections in "numberOfSectionsInTableView" as per your requirements, and then in each of the remaining methods; if the section or row in question is static just call through to super, if it's dynamic pass back the relevant details as you would in a normal UITableViewController subclass. In this example, I am simply returning nil or hard coded values.
For more information check this thread on apple forums.
- (int)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return nil;
}
- (NSString*)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
return nil;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
-(float)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 44.0f;
}
- (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
return 44.0f;
}
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44.0f;
}
- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
return nil;
}
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return nil;
}
-(int)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 5;
}
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section == 0)
return 2;
if(section == 1)
return 2;
return 5;
}
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section <= 1)
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.text = @"dynamic row";
return cell;
}
[EDIT]
You don't call super in didSelectRowAtIndexPath. It's straight forward. See below code.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int row = indexPath.row;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
//process the cell
}
Edit static grouped table view with multiple sections in Xcode Storyboard
I'm not sure if I quite understand the question, but if you're asking if you can do everything in Interface Builder, the answer is yes. After you've set the table content to 'static cells' in the Attribute Inspector, set the number of sections to the number of data sections you want, then modify each section by selecting the section, changing the header, footer, and number of rows. You can also quickly edit the header by double-clicking on it.
Each row in the section can be modified in the same way.
Related Topics
Macos on Vmware Doesn't Recognize iOS Device
Change Uitextfield and Uitextview Cursor/Caret Color
Align Text Using Drawinrect:Withattributes:
How to Use Autocorrection and Shortcut List in iOS8 Custom Keyboard
Uicollectionview with a Sticky Header
How to Make Uibutton's Text Alignment Center? Using Ib
Drawrect Circle and Animate Size/Color
Swift - Segmented Control - Switch Multiple Views
Uicollectionview's Cellforitematindexpath Is Not Being Called
Sending Push Notifications to iOS from Pwa
How to Change "Initwithnibname" in Storyboard
Change Color of Png in Buttons - iOS
Refresh Certain Row of Uitableview Based on Int in Swift
Why the Extension Is "Momd" But Not "Xcdatamodel" When Search the Path for the Model File
How to Remove All Gesture Recognizers from a Uiview in Swift