How to Deal with Dynamic Sections and Rows in iOS Uitableview

How to deal with dynamic Sections and Rows in iOS UITableView

An approach I use when creating a table where I know all the possible sections is with enums. You create an enum for each of the possible section types:

enum SectionTypes { case sectionA, sectionB, sectionC }

And then create a variable to hold the sections:

var sections: [SectionTypes]

When you have your data ready then you populate sections with the sections that needs to be displayed. I usually also make a method to help get the section:

func getSection(forSection: Int) -> SectionTypes {
return sections[forSection]
}

With this in place you can start implementing the common DataSource delegate methods:

func numberOfSections(in collectionView: UICollectionView) -> Int {
return sections.count
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch getSection(forSection: section) {
case .sectionA:
return 0 //Add the code to get the count of rows for this section
case .sectionB:
return 0
default:
return 0
}
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch getSection(forSection: indexPath.section) {
case .sectionA:
//Get section A cell type and format as your need
//etc
}
}

Dynamic sections and rows UITableView

Not tested but you can use idea of my code for separating your array

NSMutableArray *sections = [[NSMutableArray alloc] init];
NSMutableArray *elementsInSection = [[NSMutableArray alloc] init];
for (NSDictionary *dict in Array) {
NSString *day = [dict objectForKey:@"day"];
if (![sections containsObject:day]) {
[sections addObject:day];
NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr addObject:dict];
[elementsInSection addObject:arr];
} else {
NSMutableArray *arr = [elementsInSection objectAtIndex:[sections indexOfObject:day]];
[arr addObject:dict];
[elementsInSection setObject:arr atIndexedSubscript:[sections indexOfObject:day]];
}
}

And your tableview datasource is now become

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [sections count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [elementsInSection count];
}

How to perform a dynamic creation of sections and cells to a UITableView in SWIFT 3

For your information numberOfRowsInsection exists in swift3, see below

 override func numberOfSections(in tableView: UITableView) -> Int {
return section.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items[section].count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
cell?.textLabel?.text = items[indexPath.section][indexPath.row]
return cell!
}

Thanks:)

iOS: uitableview with multiple dynamic sections objective c

What you have here is (converted with NSJSONSerialization) is sponsors being a dictionary where each of dictionaries contains an array.

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSDictionary *sponsers = parsedResponse[@"sponsers"];
return sponsers.allKeys.count; // For every key we need a section
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSDictionary *sponsers = parsedResponse[@"sponsers"];
NSString *key = sponsers.allKeys[section];
return key; // The key is the section name

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *sponsers = parsedResponse[@"sponsers"];
NSString *key = sponsers.allKeys[section];
NSArray *content = sponsers[key]; // Each item should be an array
return content.count; // Return number of items in embedded array
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *sponsers = parsedResponse[@"sponsers"];
NSString *key = sponsers.allKeys[indexPath.section];
NSArray *content = sponsers[key];
NSDictionary *item = content[indexPath.row];
// We have the item. Populate the cell
... generate cell ...
cell.textLabel.text = item[@"sp_name"];
...
}

This should be all the info you need to construct your table view. If you have issues with populating cell data I suggest you ask another, specific question about it.

Swift: How to configure a tableview with multiple sections dynamically using JSON data

You can build your data structure like that:

var teams = [[String: [Datum]]]()
for team in teams {
let teamProjects = projects.filter {$0.relationships.team.id == team.id}
let teamData = [team: [teamProjects]]
teams.append(teamData)
}

and in numberOfRows method:

 let team = teamsWithProjects[section-1]
let teamProject = Array(team.values)[0]
return teamProject.count

and in cellForRow method:

  let team = teamsWithProjects[indexPath.section-1]
let teamProject = Array(team.values)[0]
projectCell.textLabel?.text = teamProject[indexPath.row].attributes.name

Hope this will help you!

How to add data dynamically to UITableView when tapped on section headers

You should redesign your model.
Model must be reflective of you UI. As section contains N number of rows so your model of section should have an Array of Row Model. So you could easily file the list of rows for particular Section. Managing Section & Row in two different Array is a headache to manage.

For Example.

struct SectionModel {
var opened: Bool!
var yourTableRowModels = [RowModel]()
}

struct RowModel {
var someAttribute: String!
}

Now in your TableViewDataSource methods use below approach.

class YourViewController: UIViewController {
var sections = [SectionModel]()

func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].yourTableRowModels.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let rowModel = sections[indexPath.section].yourTableRowModels[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "dataCell") as! DataCell
cell.chapterName.text = rowModel.someAttribute
cell.numberOfDocumentsAndAssignments.text = rowModel.someAttribute
return cell
}
}

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:

Sample Image

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.

Howto fill UITableView with sections and rows dynamically?

You could have one array for the whole table view. The array contains arrays for every section. Then the cellForRowAtIndexPath could look like:

- (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] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}

[[cell textLabel] setText: [[[myArray objectAtIndex: indexPath.section] objectAtIndex: indexPath.row]];
return cell;
}

I hope this help you in your problem.

Edit: With the modern Objective-C and ARC I would write this as

- (void)viewDidLoad {
....
[self.tableView registerClass:[MyCellClass class] forCellReuseIdentifier:kMyCellIdentifier];
}
...
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {

MyCellClass *cell = [tableView dequeueReusableCellWithIdentifier:kMyCellIdentifier forIndexPath:indexPath];

cell.textLabel.text = myArray[indexPath.section][indexPath.row];

return cell;
}


Related Topics



Leave a reply



Submit