I'm trying to embed a UITableView into a UICollectionViewCell. I'm managing to get everything to load. However, when it does load it up it seems to randomly use the last loaded value for the UITableView List Items. My DebugPrint Output seems to load all of the CollectionViewCells before even referencing the TableView. Once the CollectionViewCells are set, then it populates the TableView with whatever value it is left with. How can I resolve this so that I'm using the correct values? I suspect it is something to how I'm using IndexPath however I'm fairly new to Swift.
Populating UICollectionView
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: releaseIdentifier, for: indexPath) as! ReleaseCollectionViewCell
let vid: VideoItem
vid = Video[indexPath.item]
let rating = vid.Rating
let denominator = 2.0
let roundedRating = round(rating*denominator )/denominator
if vid.SiteVideoID != 0 {
cell.ReleaseImage.setImageFromURl(stringImageUrl: "\(file.BaseURL)/sitePictures/\(GetFilePath(ID: String(vid.SiteVideoID)))/\(String(vid.SiteVideoID)).jpg")
} else {
cell.ReleaseImage.setImageFromURl(stringImageUrl: "\(file.BaseURL)/pictures/\(GetFilePath(ID: String(vid.VideoID)))/\(String(vid.VideoID))_001.png")
}
cell.ReleaseDate.text = vid.ReleaseDate
cell.ReleaseTitle.text = vid.Title
cell.SiteLogo.setImageFromURl(stringImageUrl: "\(file.BaseURL)/siteLogos/" + String(vid.SiteID) + ".png")
if vid.VideoID == 0 {
cell.ReleaseImage.alpha = 0.5
} else {
cell.ReleaseImage.alpha = 1.0
}
indexPathItem = -1
indexPathItem = indexPath.item
debugPrint(indexPathItem)
cell.TagsView.delegate = self
cell.TagsView.dataSource = self
return cell
}
and for populating the TableView
extension MiscCollectionViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if indexPathItem != -1 {
return Video[indexPathItem].Tags.count
} else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tags = tableView.dequeueReusableCell(withIdentifier: "Tag", for: indexPath) as! TagTableViewCell
debugPrint(String(indexPathItem) + " " + Video[indexPathItem].Tags[indexPath.row])
tags.TagLabel.text = String(indexPathItem) //Video[indexPathItem].Tags[indexPath.row]
return tags
}
}
Related
I want to add eCommerce Homepage functionality to my app
Like Horizontal CollectionView(Slider) for each featured, special and selected category. I have implemented a special and featured category with slider but don't know how to add/handle dynamic data for other category collectionview ??
What i have..
var FeaturedProduct = [SubcatItemModel]()
var SpecialProduct = [SubcatItemModel]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedProductForCart = self.products[indexPath.row].productId
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell") as! CategoryTableViewCell
if(indexPath.row == 0){
//getFeaturedProduct()
cell.MyheaderName.text = "FEATURED PRODUCTS"
}
cell.cCollectionView.layer.backgroundColor = UIColor.paleGrey.cgColor
cell.cCollectionView.tag = indexPath.row
cell.cCollectionView.reloadData()
print(String(cell.cCollectionView.tag))
if(indexPath.row == 1){
self.special = 1
}else{
self.special = 0
}
return cell
}
//For CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(collectionView.tag == 0){
return self.subcatModel.count
}else if(collectionView.tag == 1){
return self.SpecialProduct.count
}else{
return 2 //here is i want dynamic collectionview item for category products
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : RelatedCell = collectionView.dequeueReusableCell(withReuseIdentifier: "RelatedProducts", for: indexPath) as! RelatedCell
let item = self.RelatedProduct[indexPath.row]
cell.ProductName.text = item.name
let modifiedUrl = item.image.replace(target: " ", withString:"%20")
let urlll = URL(string:modifiedUrl)
cell.productImage.kf.setImage(with: urlll, placeholder: UIImage(named: "noImagePlaceholder"))
cell.ProductPrice.text = item.price
return cell
}
Note: Other tutorial returning static collectionview size that i want dynamic.
Please Help....this problem makes me cry
How to set CollectionView data to Collection tag.collection tag count is not fixed .How to integarte cellForItemAt and numberOfItemsInSection in CollectionView .So I have a collectionView inside of a tableView. I would like to use the values from my array to populate each labels text inside each collectionViewCell. If I print the code below in collectionView cellForItemAt.
class testViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var providerCategoryTableView: UITableView!
let collectionReuseIdentifier = "selectServiceProviderCollectioncell" // Collection cell identifier in the storyboard
let tableReuseIdentifier = "selectServiceProviderTableViewCell"
var providerCategoryTableViewDictionary = [NSMutableDictionary]()
var providerCategoryCollectionViewDictionary = [String:Any]()
var providerCategoryDictionary = [[String:Any]]()
var ServiceResponse:[[String:Any]] = {[id:1,provider_name:”Telephone”,providers:[{category_name:”Test1”,id:”1”}, {category_name:”Test2”,id:”2”}]], [id:2,provider_name:”MobileNumber”,providers:[{category_name:”Test3”,id:”1”}, {category_name:”Test2”,id:”2”}, {category_name:”Test4”,id:”4”}, {category_name:”Test5”,id:”5”}]]}
var setIndexTag:Int = 0
var cellForItemIndexTag:Int = 0
var exapandTableViewArray = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
initControls()
}
// Expand function
func isExpandable(tableViewHeight:Int) -> Bool {
for item in exapandTableViewArray {
if(tableViewHeight == item){
return true
}
}
return false
}
// MARK: - Private
func initControls(){
providerCategoryTableView.tableFooterView = UIView()
callSelectServiceProvidersAPI()
addServiceProviderLabel.attributedText = GlobalFunctions().addNormalAndBoldText(normalText: NSLocalizedString("RecipientSelectServiceProvidersViewController.addServiceProviderNormalLabel", comment: ""), boldText: NSLocalizedString("RecipientSelectServiceProvidersViewController.addServiceProviderBoldLabel", comment: ""), fontSize : 16.0)
DontSeeYourServiceUILabel.attributedText = GlobalFunctions().addNormalAndBoldText(normalText: NSLocalizedString("RecipientSelectServiceProvidersViewController.DontSeeYourServiceUINormalLabel", comment: ""), boldText: NSLocalizedString("RecipientSelectServiceProvidersViewController.DontSeeYourServiceUIBoldLabel", comment: ""),fontSize : 16.0)
suggestAServiceUIView.layer.borderColor = UIColor( red: CGFloat(115/255.0), green: CGFloat(204/255.0), blue: CGFloat(215/255.0), alpha: CGFloat(1.0) ).cgColor
}
// MARK: - UITableView
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ServiceResponse.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: tableReuseIdentifier, for: indexPath) as! RecipientSelectServiceProviderTableViewCell
let providerCategoryObject = selectServiceProviderResponse[indexPath.row]
cell.categoryNameLabel.text = (providerCategoryObject["name"] as? String)!
cell.categoryCollectionView.delegate = self
cell.categoryCollectionView.dataSource = self
cell.categoryCollectionView.tag = indexPath.row
cell.categoryCollectionView.reloadData()
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if(isExpandable(tableViewHeight:indexPath.row)){
return 60
}else{
return 120
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath) as! RecipientSelectServiceProviderTableViewCell
let UpBlueImage = UIImage(named: "up_blue_arrow")
let UpBlueImageData = UIImagePNGRepresentation(UpBlueImage!)
let SelectedImageData = UIImagePNGRepresentation((selectedCell.UpDownImageView.image)!)
if (SelectedImageData == UpBlueImageData){
exapandTableViewArray.append(indexPath.row)
selectedCell.UpDownImageView.image = UIImage(named:"down_blue_arrow")
self.CategoryTableView.beginUpdates()
self.CategoryTableView.endUpdates()
}else{
if let index = exapandTableViewArray.index(of:indexPath.row) {
exapandTableViewArray.remove(at: index)
}
selectedCell.UpDownImageView.image = UIImage(named:"up_blue_arrow")
self.CategoryTableView.beginUpdates()
self.CategoryTableView.endUpdates()
}
}
// MARK: - UICollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return collectioncategories.count
/* if collectionView.tag == 0{
return collectioncategories.count
}else if collectionView.tag == 1{
return collectionSecondcategories.count
}*/
for obj in ServiceResponse {
if collectionView.tag == setIndexTag {
let providers:[[String: Any]] = obj["providers"] as! [[String : Any]]
return providers.count
}
setIndexTag = setIndexTag + 1
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionReuseIdentifier, for: indexPath) as! RecipientSelectServiceProviderCollectionViewCell
//cell.categoryUILabel.text = collectioncategories[indexPath.row]
/*if collectionView.tag == 0{
cell.categoryUILabel.text = collectioncategories[indexPath.row]
}else if collectionView.tag == 1{
cell.categoryUILabel.text = collectionSecondcategories[indexPath.row]
}*/
for obj in ServiceResponse {
if collectionView.tag == cellForItemIndexTag {
let providers:[[String: Any]] = obj["providers"] as! [[String : Any]]
let data = providers[indexPath.row]
print("providers",providers[indexPath.row])
print("data",data)
for provider in providers {
print("cellForItemAt provider.name",provider["name"] as! String)
cell.categoryUILabel.text! = (provider["name"] as? String)!
print("cell.categoryUILabel.text",cell.categoryUILabel.text!)
}
}
cellForItemIndexTag = cellForItemIndexTag + 1
}
return cell
}
/* func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout,sizeForItemAt indexPath: IndexPath) -> CGSize {
let nbCol = 3
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left + flowLayout.sectionInset.right + (flowLayout.minimumInteritemSpacing * CGFloat(nbCol - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(nbCol))
return CGSize(width: size, height: size)
}*/
I want
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return collectioncategories.count
if collectionView.tag == 0{
return collectioncategories.count
}else if collectionView.tag == 1{
return collectionSecondcategories.count
}
}
But 0,1....n collectionView.tag not fixed and inside array count also different.Please Its Urgent.Thanks
i have done a similar application where what we did is create one parent array
ie
var tableViewDataArray = [HomeDataHolder] () // which includes the type , sub category in my case myclass contains category name , category id and product array
after this add each category in to this array for me, added dataArry[banners,toppicks,.....]
this is how added class object to arraya
if let categoryes = JSON["categories"] as? NSArray{
for index in 0..<categoryes.count{
self.categoryArray.add(categoryes[index])
}
print(self.categoryArray)
self.session.saveCategory(self.categoryArray)
let catObject = HomeDataHolder(type:"CATEGORY").addCategoryes(categoryArray: self.categoryArray)
self.tableViewDataArray.append(catObject)
}
set tableview datasource as this array
if you need different type design design different cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let homeData = tableViewDataArray[indexPath.row] as! HomeDataHolder
if homeData.type == "CATEGORY"{
let cell = tableView.dequeueReusableCell(withIdentifier: "category_name_cell", for: indexPath) as! HomeCategoryTableViewCell
cell.selectionStyle = .none
let dataArray = homeData.dataArray
cell.setProducArray(dataArray!)
cell.delegate = self
return cell
}else if .......
in my HomeCategoryTableViewCell class
func setProducArray(_ data:NSMutableArray){
for index in 0..<data.count{
dataArray.add(data[index])
}
colectionView.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "home_categoryes_cellection_cell", for: indexPath) as! HomeCategoriesCollectionViewCell
if let dataDictionary = dataArray[indexPath.row] as? NSDictionary{
utility.setCornerRadius([cell.containerView], cornerRadies: 19)
cell.categoryNameLabel.text = dataDictionary.getStringValue("name")
print(dataDictionary.getStringValue("name"))
}
return cell
}
and my HomeCategoryTableViewCell contains a collection view cell.setProducArray(dataArray!) will change the datasource of the collectionview
In your cellForRow of the TableView access the collectionView with viewWithTag and then give it the indexPath.row in the accessiblityHint property and call reload. Then in the your numberOfSections, numberOfItems or cellForItem methods of collectionView you can access the accessiblityHint property and access your array's index to display the data you want.
I am currently using two prototype cells to have my collectionView in top cell moving horizontally while all other cells moves vertical. It's still short one cell count at the bottom and I can't seem to figure out why.
This is the code. Can you point out where the issue is please?
//Mark:- Data arrays
var dataArray: [String] = ["c1","c2","c3","c4","c5"]
var cellArray: [String] = ["10","11","12","13","14","15"]
//Mark:- UITableView Delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
return cell
} else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell2.cellImage.image = UIImage(named: cellArray[indexPath.row])
return cell2
}
}
//Mark:- UICollectionView Delegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InsideCollectionViewCell", for: indexPath) as! InsideCollectionViewCell
cell.myImage.image = UIImage(named: dataArray[indexPath.row])
return cell
}
It seems you want your table view to contain the values in your cellArray array plus one extra special row at index 0.
In order to do this you need to indicate that there is an extra row and your indexing needs to account for the extra row.
But a simpler approach is to use multiple sections in your table view. Use section 0 for the extra special row and use section 1 for the values in your cellArray.
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return section == 0 ? 1 : cellArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
return cell
} else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell2.cellImage.image = UIImage(named: cellArray[indexPath.row])
return cell2
}
}
Make sure you adjust for the use of multiple sections in any other table view method you may implement (such as didSelectRowAt, etc.).
For the sake of comparison, here is how you would need to change your code if you want all of the rows in one section:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellArray.count + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
return cell
} else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell2.cellImage.image = UIImage(named: cellArray[indexPath.row - 1])
return cell2
}
}
Image 1:
I have a collection view and a table view in the same view controller. I want to update the data of my table view, based on the selected item in the collection view. So every time I click on any item of the collectionView, my tableView data should update.
My code:
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
for superSkill in skills!{
if superSkill.name == (skills?[indexPath.row].name)! {
childSkills = superSkill.skills!
}
}
DispatchQueue.main.async{
self.childSkillTableView.reloadData()
}
}
Is there any way i can achieve it
First thing is to make sure your childSkillTableView.dataSource = self and your superSkillsCollectionView.delegate = self
The second thing, there's no reason to use DispatchQueue.main.async({})
The third thing, though less important, instead of a for loop, you might use something like:
childSkills = skills?.first(where { superSkill in superSkill.name == (skills?[indexPath.row].name)! }
Though you should use some if let or guard let statements to check for optionals instead of force unwrapping.
extension PerformanceVC: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return skills.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "superSkillCell", for: indexPath) as! SuperSkillCell
cell.superSkillName.text = skills[indexPath.row].name
//loading image async
ImageAsyncLoader.loadImageAsync(url: (skills[indexPath.row].imageURL)!, imgView: cell.superSkillImage)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
return CGSize(width: skillCollections.frame.height * 0.9, height: skillCollections.frame.height) //use height whatever you wants.
}
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print((skills[indexPath.row].name)!)
for skill in skills{
if skill.name == (skills[indexPath.row].name)! {
childSkills = skill.skills!
}
}
self.subSkillTableView.reloadData()
}
}
extension PerformanceVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let openViewHeight: Int = 55
if (indexPath.row == selectedRowIndex.row && isExpanded == false){
isExpanded = true
return CGFloat(openViewHeight + 36 * (childSkills[indexPath.row].skills?.count)!)
} else if (indexPath.row == selectedRowIndex.row && isExpanded == true){
isExpanded = false
return CGFloat(openViewHeight)
} else {
isExpanded = false
return CGFloat(openViewHeight)
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return childSkills.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(childSkills[indexPath.row].name)
selectedRowIndex = indexPath
tableView.beginUpdates()
//let cell = tableView.dequeueReusableCell(withIdentifier: "SubSkillTableCell", for: indexPath) as! SubSkillTableCell
let cell = tableView.cellForRow(at: indexPath) as! SubSkillTableCell
for subview in cell.grandSkillStack.subviews {
subview.removeFromSuperview()
}
var grandSkillView: GrandChildSkillItem
grandChildSkills = (childSkills[indexPath.row].skills)!
for grandchildskill in grandChildSkills {
grandSkillView = GrandChildSkillItem(frame: CGRect(x: 0, y: 0, width: 300, height: 30))
grandSkillView.grandChildSkillNameLabel.text = grandchildskill.name
grandSkillView.grandChildSkillProgress.progress = Float(grandchildskill.percentage!)
cell.grandSkillStack.addArrangedSubview(grandSkillView)
}
tableView.endUpdates()
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//tableView.separatorStyle = .none
tableView.showsVerticalScrollIndicator = false
let cell = tableView.dequeueReusableCell(withIdentifier: "SubSkillTableCell", for: indexPath) as! SubSkillTableCell
cell.subSkillName.text = childSkills[indexPath.row].name
cell.subSkillProgress.progress = Float(childSkills[indexPath.row].percentage!)
if let uPoints = childSkills[indexPath.row].userPoints {
if let tPoints = childSkills[indexPath.row].totalPoints {
if let count = childSkills[indexPath.row].skills?.count {
cell.subSkillDetail.text = "\(uPoints)" + "/" + "\(tPoints)" + "XP \u{2022} " + "\(count)" + " subskills"
}
}
}
return cell
}
}
I am currently having a problem with displaying two different types of custom cells on the same uitableview.
What I have managed so far, is receiving the "updates" to the update cell, known as cell. I just cannot figure out how to also get numberOfRowsInSection to return two values, so both of my cells will show.
Let me explain through my code:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return updates.count
return updatesTask.count // I CANNOT DO THIS - what can I do instead?
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
let update = updates[indexPath.row]
let updateTask = updatesTask[indexPath.row]
// Example of the two different cells that need different data from firebase
cell.nameLabel.text = update.addedByUser
cellTask.nameLabel.text = updateTask.addedByUser
As you can probably see, the let updateTask is trying to get an indexPath.row but that is not possible, since I cannot have two return values in the numberOfRowsInSection, which is a problem because that number is referring to the place where the data is stored in my firebase database.. How can I modify this to make it work?
Hope you guys understand where I am going with this, otherwise let me know and I will try to explain better :-)
#Callam's answer is great if you want to put them in two sections.
This is the solution if you want all to be in one section.
First, in numberOfRowsInSection method you need to return the sum of those two array counts like this: return (updates.count + updatesTask.count)
Then you need to configure cellForRowAtIndexPath method like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row < updates.count{
// Updates
let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
let update = updates[indexPath.row]
cell.nameLabel.text = update.addedByUser
return cell
} else {
// UpdatesTask
let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
let updateTask = updatesTask[indexPath.row-updates.count]
cellTask.nameLabel.text = updateTask.addedByUser
return cellTask
}
}
This will display all cells followed by all cellTasks.
If updates array and updatesTask array have equal number of items and you want to display them one by one you can use this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row % 2 == 0 {
// Updates
let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
let update = updates[indexPath.row/2]
cell.nameLabel.text = update.addedByUser
return cell
} else {
// UpdatesTask
let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
let updateTask = updatesTask[indexPath.row/2]
cellTask.nameLabel.text = updateTask.addedByUser
return cellTask
}
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return updates.count
case 1:
return updatesTask.count
default:
return 0
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
let update = updates[indexPath.row]
cell.nameLabel.text = update.addedByUser
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
let updateTask = updatesTask[indexPath.row]
cell.nameLabel.text = updateTask.addedByUser
return cell
default:
return UITableViewCell()
}
}
For each row you have to choose if you want to display one type of cell or the other but not both. You should have a flag in numberOfRowsInSection telling your method that you want to load Cell or CellTask and then return the correct number of rows.
You should return total number of rows in your numberOfRowsInSection method. so you can return summation of your both array's count something like,
return updates.count + updatesTask.count
now in your cellForRowAtIndexPath method you can differentiate your cell something like,
let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
if indexPath.row % 2 == 1 {
//your second cell - configure and return
return cellTask
}
else
{
//your first cell - configured and return
return cell
}
I am not sure what you want to achieve. If you want to display the number of cells updates[] and updatesTask[] have elements you can do it like this
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (updates.count + updatesTask.count)
}
then you can modify your cellForRowAtIndexPath method like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:updateTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! updateTableViewCell
let cellTask:tasksTableViewCell = tableView.dequeueReusableCellWithIdentifier("TaskCell", forIndexPath: indexPath) as! tasksTableViewCell
if indexPath.row < updates.count{
//update
let update = updates[indexPath.row]
cell.nameLabel.text = update.addedByUser
}else{
let updateTask = updatesTask[indexPath.row]
cellTask.nameLabel.text = updateTask.addedByUser
}
return cell
}
with the if condition you can choose from which array you are taking data.
But be careful to name an array exactly the same as another constant like you did here
let updateTask = updatesTask[indexPath.row]
You can create a simple View Model, that will hold the multiple item types:
enum ViewModelItemType {
case nameAndPicture
case about
case email
case friend
case attribute
}
protocol ViewModelItem {
var type: ViewModelItemType { get }
var rowCount: Int { get }
var sectionTitle: String { get }
}
Then create a model item type for each section. For example:
class ViewModelNameAndPictureItem: ViewModelItem {
var type: ProfileViewModelItemType {
return .nameAndPicture
}
var sectionTitle: String {
return “Main Info”
}
var rowCount: Int {
return 1
}
var pictureUrl: String
var userName: String
init(pictureUrl: String, userName: String) {
self.pictureUrl = pictureUrl
self.userName = userName
}
}
Once you configure all your section items with, you can save them in ViewModel:
class ProfileViewModel {
var items = [ViewModelItem]()
}
And add to you TableViewController:
let viewModel = ViewModel()
In this case, NumberOfSections, NumberOfRows and CellForRowAt methods will be clean and simple:
override func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.items.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.items[section].rowCount
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = viewModel.items[indexPath.section]
switch item.type {
// configure celll for each type
}
}
Configuring the section title will also be very neat:
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return viewModel.items[section].sectionTitle
}
Please check my recent tutorial on this topic, that will answer your question with the details and examples:
https://medium.com/ios-os-x-development/ios-how-to-build-a-table-view-with-multiple-cell-types-2df91a206429