I know you cannot mix Static and Dynamic cell types in a single UITableView
but I couldn\'t think of a better way to describe my issue.
I have several p
suraj k thomas, Have a look on this structure of mine, and works perfectly. @firecast I didn't use constraints within this project, however I did set the height of the container based on the container's tableview height like so:
ContainerViewController *containerVC = self.childViewControllers.firstObject;
CGRect frame = self.containerView.frame;
frame.origin.x = 0;
frame.origin.y = 0;
frame.size.width = self.tableView.frame.size.width;
frame.size.height = containerVC.tableView.contentSize.height;
self.containerView.frame = frame;
[self.tableView setTableHeaderView:self.containerView];
Hope this helps, let me know if you have any question.
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;
}
}
Add a new hidden UITableView holding your Dynamic cells
Steps:
1- In your main UITableViewController
append new Section
at the end,
Inside this Section
add only one UITableViewCell
,
Insert a new UITableView
inside the Cell.
let us call the new table tblPrototypes
because
it will be the holder for the Prototype cells.
2- Now set the type of tblPrototypes
to Dynamic Prototypes,
Then add as many prototype UITableViewCell
s as you need.
3- Add an Outlet for tblPrototypes
in the main controller of the Main Static UITableView
,
let us call it tablePrototypes
and of course it is of type UITableView
Coding part:
First make sure to hide tblPrototypes
from the UI,
Since it's the last section in your Main Table, you can do this:
@IBOutlet weak var tblPrototypes: UITableView!
override func numberOfSections(in tableView: UITableView) -> Int {
return super.numberOfSections(in: tableView) - 1
}
The last section will not be presented.
Now when ever you want to display a dynamic cell you do that:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let needDynamic = true
if !needDynamic {
return super.tableView(tableView, cellForRowAt: indexPath)
}
let cellId = "dynamicCellId1"
let cell = self.tblPrototypes.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
// configure the cell
return cell
}
After struggled for 1 day, found best solution
Updated for Swift 4
for the case of the question:
Add a empty tableview cell in the second section which you want to apply the dynamic cells, change identifier of the cell as WiFiTableViewCell
create a new XIB file called WiFiTableViewCell
register the Nib in the function ViewDidLoad in tableViewController
tableView.register(UINib(nibName: "WiFiTableViewCell", bundle: nil), forCellReuseIdentifier: "WiFiTableViewCell")
add the following code to use both dynamic and static cell
override func numberOfSections(in tableView: UITableView) -> Int
{
return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 1 {
return self.dataSource.count
//the datasource of the dynamic section
}
return super.tableView(tableView, numberOfRowsInSection: section)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "WiFiTableViewCell") as! WiFiTableViewCell
return cell
}
return super.tableView(tableView, cellForRowAt: indexPath)
}
override func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: NSIndexPath) -> Int {
if indexPath.section == 1 {
let newIndexPath = IndexPath(row: 0, section: indexPath.section)
return super.tableView(tableView, indentationLevelForRowAt: newIndexPath)
}
return super.tableView(tableView, indentationLevelForRowAt: indexPath)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 1 {
return 44
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
Best and Easiest Way Yet
1) Place Two Container Views in the Header and in the Footer of a Dynamic TableView 2) Assign the Static TableViews to these Containers and Untick the "Scrolling Enabled"
Please check out my illustration at https://stackoverflow.com/a/22524085/1537178
Implement your tableView as normal using dynamic prototypes. For each custom cell, use 1 prototype. For an easy example, we'll use 2 cells, AddCell and RoomCell. AddCell is going in the first row, and RoomCell in the 2nd and any cell below.
Remember to increase your count at numberofRowsInSection
by the appropriate number of static cells (in this case 1). So if you're returning the count of an array to determine the number of rows, it'd be return array.count + 1
for this example since we have 1 static cell.
I usually create a custom class for each cell as well. This typically makes it simpler to configure cells in the View Controller, and is a good way to separate code, but is optional. The example below is using a custom class for each cell. If not using a custom class, replace the if let statement with an if statement without an optional cast.
note: configureCell
below is a method in the custom class RoomCell
that dynamically configures the cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
if let cell = tableView.dequeueReusableCell(withIdentifier: "AddCell", for: indexPath) as? AddCell {
return cell
}
} else {
if let cell = tableView.dequeueReusableCell(withIdentifier: "RoomCell", for: indexPath) as? RoomCell {
cell.configureCell(user: user, room: room)
return cell
}
}
return UITableViewCell() //returns empty cell if something fails
}