Creating sections with headers with two dynamic tableviewcells in Swift - ios

I have a table view with two cells, "electionInfo" and "candidates". Candidates returns an array of the candidates, while electionInfo gives a single text body (so just one cell). I'd like to divide them into two sections with their respective headers. Right now, it gives me one header for both cells. How do I fix it?
Thanks!!
My code...
#IBOutlet weak var table: UITableView!
var info: [PFObject] = []
var items: [PFObject] = []
let titles = ["Election Info", "Candidates"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count + 1
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return titles[section]
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == self.items.count {
let cell = table.dequeueReusableCellWithIdentifier("candidateCell") as! CandidateTableViewCell
let candidate = items[indexPath.row]
cell.candidateImage.file = candidate["image"] as! PFFile
cell.candidateImage.loadInBackground()
cell.candidateName?.text = candidate["name"] as! String
cell.candidateParty?.text = candidate["partyAffiliation"] as! String
return cell
} else {
let cell = table.dequeueReusableCellWithIdentifier("electionCell") as! ElectionInfoTableViewCell
cell.electionInfo.text = "hey there"
}
}
}

internal func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2 //or the number of sections you have
}
internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = UITableViewCell()
if indexPath.section == 0 {
let candidateCell = table.dequeueReusableCellWithIdentifier("candidateCell") as! CandidateTableViewCell
let candidate = items[indexPath.row]
cell.candidateImage.file = candidate["image"] as! PFFile
cell.candidateImage.loadInBackground()
cell.candidateName?.text = candidate["name"] as! String
cell.candidateParty?.text = candidate["partyAffiliation"] as! String
return candidateCell
} if indexPath.section == 1 {
let electionCell = table.dequeueReusableCellWithIdentifier("electionCell") as! ElectionInfoTableViewCell
cell.electionInfo.text = "hey there"
return electionCell
}
return cell
}
then you have also to change your numberOfRowsInSection
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if section == 0 {
return self.items.count
}
if section == 1 {
return self.items.count // or the number of rows you have in that section
}
}

A section and a cell is different thing in tableview. Right now your code gives you section instead of cell because you return self.items.count + 1 in numberOfSectionsInTableView. A fix for this;
Since your tableview should contain two section only you must return 2 or titles.count in numberOfSectionsInTableView
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.titles.count
}
Next return corresponding array count in numberOfRowsInSection
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return self.info.count
}else{
return self.items.count
}
}
And finally in cell for row at index path return cell based on a section:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 1 {
let cell = table.dequeueReusableCellWithIdentifier("candidateCell") as! CandidateTableViewCell
let candidate = items[indexPath.row]
cell.candidateImage.file = candidate["image"] as! PFFile
cell.candidateImage.loadInBackground()
cell.candidateName?.text = candidate["name"] as! String
cell.candidateParty?.text = candidate["partyAffiliation"] as! String
return cell
} else {
let cell = table.dequeueReusableCellWithIdentifier("electionCell") as! ElectionInfoTableViewCell
cell.electionInfo.text = "hey there"
}
}

Related

Adding two Custom cells in tableView

I have a tableView on mainStoryboard with two custom cells.
I would like to set two more cells at different row.
However When I implemented the code the added cells replaces original cells. (Custom cell of "Basic grammar3" and "Basic grammar5" are disappearing.)
I was trying to find the answer but could not find out.
I have image and code added below.
import UIKit
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tblStoryList: UITableView!
var array = PLIST.shared.mainArray
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.array.count + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 || indexPath.row == 3 || indexPath.row == 5 {
let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath) as! HeaderCell
cell.headerTitle.text = indexPath.row == 0 ? "First Stage" : indexPath.row == 3 ? "Second Stage" : "Third Stage"
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "StoryTableviewCell", for: indexPath) as! StoryTableviewCell
//making plist file
let dict = self.array[indexPath.row - 1]
let title = dict["title"] as! String
let imageName = dict["image"] as! String
let temp = dict["phrases"] as! [String:Any]
let arr = temp["array"] as! [[String:Any]]
let detail = "progress \(arr.count)/\(arr.count)"
//property to plist file をつなぐ
cell.imgIcon.image = UIImage.init(named: imageName)
cell.lblTitle.text = title
cell.lblSubtitle.text = detail
cell.selectionStyle = UITableViewCellSelectionStyle.none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
return
}
tableView.deselectRow(at: indexPath as IndexPath, animated:true)
if indexPath.row == 3 {
return
}
tableView.deselectRow(at: indexPath as IndexPath, animated:true)
if indexPath.row == 5 {
return
}
tableView.deselectRow(at: indexPath as IndexPath, animated:true)
let messagesVc = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
messagesVc.object = self.array[indexPath.row - 1]
self.navigationController?.show(messagesVc, sender: self)
}
You could use sections for your table view. Now, you are returning 1 in your numberOfSections function. And it is creating only one section. If you want to use headers, you can use sections for your need. And also you can fill your table view cells with multidimendional arrays. For example:
For adjusting your section headers:
let lessonTitles = ["First Stage", "Second Stage"]
Titles for sections:
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section < lessonTitles.count {
return lessonTitles [section]
}
return nil
}
For adjusting your sections and rows:
let lessons = [["Basic Grammar 1", "Basic Grammar 2"], ["Basic Grammar 3", "Basic Grammar 4"]]
Number of sections function should be:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return lessons.count
}
Number of rows in section should be:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lessons[section].count
}
And creating your cells is like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellText = data[indexPath.section][indexPath.row]
...
}
Try like this...
func numberOfSections(in tableView: UITableView) -> Int
{
return numberOfStages
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return numberOfRowsInCurrentStage
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return customizedCell
}
func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
return requiredHeight
}
func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView?
{
return stageCountView
}
You can use viewForHeaderInSection if you want to show stage count on top.
edit: The comment by raki is the much better solution (use headers). I leave this here in case you want something closer to your existing implementation.
You have to change your numbering scheme in order to insert these additional rows (and not replace existing rows). So you might want to adjust the row for the "normal" elements like this:
func adjustRow(_ row: Int) -> Int {
if row < 3 {
return row
} else if row < 5 {
return row+1
} else {
return row+2
}
}

Populate items in tableView cell from a class model error?

I have the following class model for the items. I am displaying itemsName,itemprice in sections. And Addonname and AdddonPrice in cell based on the index.. the number of sections and the number of cells are coming correctly from the class modal. sections data are also working fine. The problem is to display addon data into customTableCell.
class Cart{
var itemID:AnyObject?
var itemName:AnyObject?
var itemPrice:AnyObject?
var cartAddon:[AnyObject?]
init(itemID:AnyObject?,itemName:AnyObject?,itemPrice:AnyObject?,cartAddon:[AnyObject?]){
self.itemID = itemID
self.itemName = itemName
self.itemPrice = itemPrice
self.cartAddon = cartAddon
}
}
class CartAddon {
var addonID:Int?
var addonName:String?
var addonPrice:Double?
init(addonID:Int?,addonName:String?, addonPrice:Double?){
self.addonID = addonID
self.addonName = addonName
self.addonPrice = addonPrice
}
}
Tableview code
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return cartArray.count
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 50
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCellWithIdentifier("cartheadercell") as! cartHeaderCell
header.ItemnameLbl.text = cartArray[section].itemName as? String
header.ItemPriceLbl.text = (cartArray[section].itemPrice as! String)
return header
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cartArray[section].cartAddon.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 30
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cartcell", forIndexPath: indexPath) as! AddonCell
//error in this part
let cart: Cart = cartArray[indexPath.row].cartAddon[indexPath.row]
if let name = cart.cartAddon[indexPath.row]!["AddonName"]{
cell.AddonNameLbl.text = (name as! String)
}
cell.AddonPriceLbl.text = "£ 0.0"
return cell
}
The data is coming in this form which I have to display is:
Optional(9 Inch Thin & Crispy Margarita)
Optional(£3.40)
Optional(1749)
[Optional(Chicos_Pizza.CartAddon), Optional(Chicos_Pizza.CartAddon), Optional(Chicos_Pizza.CartAddon), Optional(Chicos_Pizza.CartAddon)]
The problem is you need to use indexPath.section to access the Cart object from array not indexParh.row, so change your cellForRowAtIndexPath code like this.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cartcell", forIndexPath: indexPath) as! AddonCell
if let cartAddon = cartArray[indexPath.section].cartAddon[indexPath.row] as? CartAddon, let name = cartAddon.addonName {
cell.AddonNameLbl.text = name
}
else {
cell.AddonNameLbl.text = "Set here some default value or blank string"
}
cell.AddonPriceLbl.text = "£ 0.0"
return cell
}

fatal error: index out of range tableview with two sections

I'm trying to populate a tableView with 2 sections using two arrays of Firebase objects (called snapshots). I'm getting an error in my cellForRowAtIndexPath function when I try to load the tableView: fatal error: Index out of range.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PersonCell", forIndexPath: indexPath) as! PersonCell
//set cell text
let guardianDict = guardians[indexPath.row].value as! [String : AnyObject] // error happens here
let dependentDict = dependents[indexPath.row].value as! [String : AnyObject]
cell.personName.text = "test"
return cell
}
Here is how I define my sections:
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch(section){
case 0: return "Dependents"
case 1: return "Guardians"
default: return ""
}
}
Any ideas?
Thanks!
EDIT: Adding the numberOfSections and numberOfRowsInSection:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
switch(section){
case 0: return self.dependents.count
case 1: return self.guardians.count
default: return 1
}
}
You have two sections in your table with each section coming from different sources. You need to add checking in your cellForRowIndexPath function to access the right array:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PersonCell", forIndexPath: indexPath) as! PersonCell
if indexPath.section == 0
{
let dependentDict = dependents[indexPath.row].value as! [String : AnyObject]
}
else if indexPath.section == 1
{
let guardianDict = guardians[indexPath.row].value as! [String : AnyObject] // error happens here
}
cell.personName.text = "test"
return cell
}
Your two arrays may be of different sizes, so in cellForRowAtIndexPath you need to check which section you are returning a cell for and only access the appropriate array. Currently you are accessing both arrays for each call to this function, resulting in index out of range exceptions when one of the arrays is smaller than the other.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("PersonCell", forIndexPath: indexPath) as! PersonCell
if indexPath.section == 0 {
let dependentDict = dependents[indexPath.row].value as! [String : AnyObject]
cell.personName.text = dependentDict["name"] as! String //Or whatever element in the dictionary is needed
} else {
let guardianDict = guardians[indexPath.row].value as! [String : AnyObject]
cell.personName.text = guardianDict["name"] as! String //Or whatever element in the dictionary is needed
}
return cell
}

Creating multiple sections with custom cells

So I have 2 custom cells inside a table view. Each cell has it's own individual section, "Filter" and "Sort By"
func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("FilterCell") as! FilterCell
// Edit cell here
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("SortByCell") as! SortByCell
// Edit cell here
return cell
}
}
func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int {
return 1
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2 }
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0:
return "Sort By"
default:
return "Filter"
}
}
I'm trying to display each section with these headers but the problem is that both sections display the same custom cell. My assumption is that I need each section to detect what custom cell to display through the identifier but I can't seem to figure this out. I'm not sure if i should be using a switch statement neither but does seem plausible
Please dude...
func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("SortByCell") as! SortByCell
// Edit cell here
return cell
}
let cell = tableView.dequeueReusableCellWithIdentifier("FilterCell") as! FilterCell
// Edit cell here
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int {
return 1
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 0:
return "Sort By"
default:
return "Filter"
}
}

Xcode - TableView - Multiple sections

I have multiple sections in my TableView and I'm a bit stuck to display there names in the correct section. I'm new to xcode, so this an easy one for most but not for me :s
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
if section == 0 {
return areas.bars.count
} else {
return areas.clubs.count
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("barsandclubsIdentifier", forIndexPath: indexPath)
if section == 0 { // **This is where I'm stuck I can't put section -> UITableViewCell**
let bars = areas.bars
let bar = bars[indexPath.row]
cell.textLabel?.text = bar.name
return cell
} else {
let clubs = areas.clubs
let club = clubs[indexPath.row]
cell.textLabel?.text = club.name
}
}
Try this may help you :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("barsandclubsIdentifier", forIndexPath: indexPath)
if indexPath.section == 0 { // **This is where I'm stuck I can't put section -> UITableViewCell**
let bars = areas.bars
let bar = bars[indexPath.row]
cell.textLabel?.text = bar.name
}else {
let clubs = areas.clubs
let club = clubs[indexPath.row]
cell.textLabel?.text = club.name
}
return cell
}

Resources