How to use multiple custom cells (>1) in UITableView - ios

I've searched for an answer to this question all over Stack Overflow and have found some useful answers but my situation is different as the number of rows in the section are to be determined from the number of items listed in an array. I'm trying to create a table that uses two custom cells. The first cell displays profile information while the second displays the news feed.
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myProfileDM.profileArray.count
//return myProfileFeedDM.profileFeedArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("bio", forIndexPath:indexPath) as! ProfileTableViewCell
cell.followerNumber!.text = myProfileDM.profileArray[indexPath.row].followerNumberInterface
cell.followers!.text = myProfileDM.profileArray[indexPath.row].followersInterface
cell.following!.text = myProfileDM.profileArray[indexPath.row].followingInterface
cell.followingNumber!.text = myProfileDM.profileArray[indexPath.row].followingNumberInterface
return cell
}
else{
let cell = tableView.dequeueReusableCellWithIdentifier("feed", forIndexPath:indexPath) as! FeedTableViewCell
//let cell: FeedTableViewCell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "feed")
cell.profileFeedLabel!.text = myProfileFeedDM.profileFeedArray[indexPath.row].profileFeed
cell.profileDateLabel!.text = myProfileFeedDM.profileFeedArray[indexPath.row].profileDate
return cell
}
}
}
when I run the program, the first cell (with identifier-bio) is the only one that loads/shows up.

I suppose the number of rows in the section is wrong. From your variable names I suspect it should be
myProfileFeedDM.profileFeedArray.count + 1
Note that in the feed array you would have to use indexPath.row - 1 to get to the right index of your array because the first row is for the profile.

I don't see any reason from the code why it doesn't work.
Try to debug cellForRowAtIndexPath method to see what is the value of the indexPath on each call
(or just put println ("IndexPath: \(indexPath)") to your cellForIndexPath method)
PS: But as long as you need your profile cell only once - I would suggest to move ProfileCell into table's or Section's header
it would be a bit more logical I think.

Related

How to add a "Load More" cell that when pressed adds more rows to the tableview?

I'm trying to create a tableview only initially shows 5 cells plus a "load more" cell when is pressed more cells will be presented. I'm downloading JSON data and splitting it into 3 arrays, one for the total data, one for data for only the first 5 cells and one for the remaining data after the first 5 cells' data is subtracted from the total data.
I saw this question on here: Load More Cells and tried implementing what they did but with little success. This is what we have so far -
pretty simple, straightforward storyboard with 2 different cells, the first one is the "test cell" which contains the JSON data, the second one is the "expand cell" that when pressed is supposed to show the rest of the cells. Here is my code so far, I omitted a lot of it to keep this post short, I'm currently getting an error it's marked:
var castArray: [CastData?]? = []
var first5CastArray: [CastData?]? = []
var remainderCastArray: [CastData?]? = []
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let firstArray = first5CastArray {
return firstArray.count + 1
} else {
return 0
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row < (first5CastArray?.count)! {
let testCell = tableView.dequeueReusableCell(withIdentifier: "testCell", for: indexPath) as! TestCell
testCell.castImageView.image = first5CastImageArray?[indexPath.row]
return testCell
} else {
let expandCell = tableView.dequeueReusableCell(withIdentifier: "expandCell", for: indexPath) as! ExpandCell
expandCell.moreLabel.text = "More"//Error here -fatal error: unexpectedly found nil while unwrapping an Optional value
return expandCell
}
}
//Below code never tested because of fatal error from cellForRowAt indexPath!!!!!
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let remainderArray = remainderCastArray {
for info in remainderArray {
first5CastArray?.append(info)
}
}
expandCell.isHidden = true
tableview.reload
}
I'm not completely sure if I'm going about this the right way, any help is appreciated!
Go back to your storyboard, select that cell again, go to "Attributes Inspector" tab, type in expandCell in identifier field.

Variable use of multiple custom cells

I'm using a unclickable tableView to display different information of one object.
For this informations I have different custom cell types one where I placed a map, if my object have locations, one have a list with links, and another a multiple line label for a little description...for example.
I manage this cells with:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell: mapCell = tableView.dequeueReusableCellWithIdentifier("mapCell") as! MapCell
return cell
} else if indexPath.row == 1 {
let cell: textCell = tableView.dequeueReusableCellWithIdentifier("textCell") as! TextCell
return cell
} else if indexPath.row == 2 {
let cell: listCell = tableView.dequeueReusableCellWithIdentifier("listCell") as! ListCell
return cell
}
}
So far so good, everything working fine. My problem is, not every object needs a map, some of them just need some text and a list, other objects need a map and a list, other all of them. I want my tableView to skip some cells if there is a condition.
I know, I can make an symbolic array for changing the number of cells of my tableView, but that deleting just from the end of my tableView, not specific cells.
One of my ideas is to generate a empty cell, maybe with a height of 0 or 1 so that I can do something like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
if mapCellNeeded {
let cell: mapCell = tableView.dequeueReusableCellWithIdentifier("mapCell") as! mapCell
} else {
let cell: emptyCell = tableView.dequeueReusableCellWithIdentifier("emptyCell") as! EmptyCell
}
return cell
} else if indexPath.row == 1 {
...
}...
}
put I don't know if there isn't an efficient way. Hope you guys can help me.
Your solution would work. Another approach (very nice and swifty) would be not to hardcode row numbers, but rather use enum instead:
enum InfoCellType {
case Map
case Text
case Links
}
...
var rows = [InfoCellType]()
...
// when you know what should be there or not
func constructRows() {
if (mapCellNeeded) {
rows.append(InfoCellType.Map)
}
rows.append(InfoCellType.Text)
... etc
}
Then in the table view methods just see what's the type for current indexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellType: InfoCellType = self.rows[indexPath.row]
switch cellType {
case .Map:
let cell: mapCell = tableView.dequeueReusableCellWithIdentifier("mapCell") as! mapCell
return cell
case .Text:
...
case.Links:
...
}
}
This solution also allows to easily change order of rows - just change the order of items in rows array.

Multiple cell prototypes in Dynamic TableView

I want to create a table like this in which on there will be two cells in one section. In first cell the profile image comes and description in the second cell. what I have tried so far is I have set Prototypes to 2 and give each prototype a unique identifier and also created two classes for two prototypes. But The problem is it is showing two rows but both rows have same data.
var profileImage = ["angelina","kevin"]
var userName = ["Angelina Jolie","Vasiliy Pupkin"]
var requestTitle = ["I have a Wordpress website and I am looking for someone to create a landing page with links and a cart to link up.","second description"]
var date = ["Feb 03, 16","Feb 03, 16"]
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return profileImage.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return profileImage.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if(indexPath.row==0){
let cell = tableView.dequeueReusableCellWithIdentifier("firstCustomCell", forIndexPath: indexPath) as! FirstProductRequestTableViewCell
cell.userNameLabel.text = userName[indexPath.row]
cell.profileImage.image = UIImage(named: profileImage[indexPath.row])
return cell
}else{
let cell = tableView.dequeueReusableCellWithIdentifier("secondCustomCell", forIndexPath: indexPath) as! SecondProductRequestTableViewCell
cell.requestTitleTxtView.text = requestTitle[indexPath.row]
return cell
}
}
Here is solution for your question.
You need to use UITableViewSecionHeaderView in this case because i think in your scenario you have multiple descriptions against a profile so put the SecionHeader which contain the information of profile and cells contain the description.
But if you want to Repeat the whole cell then you only need to make a CustomCell which contain profile information and description with a line separator. You can make a line separator with an Image or using UIView of height 1.0 and colour lightgray.
Based on your description, the number of sections returned is correct, but you should return 2 for the number of rows in each section and when configuring the cells you should be using indexPath.section where you're currently using the row to choose the data to add to the cell (but keep using the row to choose which type of cell to return).
So, the section is used to choose which person you're showing details about and the row is used to choose which piece of information to show:
var profileImage = ["angelina","kevin"]
var userName = ["Angelina Jolie","Vasiliy Pupkin"]
var requestTitle = ["I have a Wordpress website and I am looking for someone to create a landing page with links and a cart to link up.","second description"]
var date = ["Feb 03, 16","Feb 03, 16"]
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return profileImage.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if(indexPath.row == 0) {
let cell = tableView.dequeueReusableCellWithIdentifier("firstCustomCell", forIndexPath: indexPath) as! FirstProductRequestTableViewCell
cell.userNameLabel.text = userName[indexPath.row]
cell.profileImage.image = UIImage(named: profileImage[indexPath.section])
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("secondCustomCell", forIndexPath: indexPath) as! SecondProductRequestTableViewCell
cell.requestTitleTxtView.text = requestTitle[indexPath.section]
return cell
}
}

When UITableView Scrolling Returned Wrong IndexPath.Row Value

This is my codes;
// MARK: - Table View Delegate && Data Source Methods
// **************************************************
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let index = indexPath.row
print(index)
if index == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("HeaderCell", forIndexPath: indexPath)
cell.backgroundColor = ColorHelper.getCellBackgroundColor()
return cell
}
else {
if let cell = tableView.dequeueReusableCellWithIdentifier("GradeCell", forIndexPath: indexPath) as? GradeCell {
cell.activeViewController = self;
cell.gradeButton.tag = index
cell.creditButton.tag = index
cell.lessonNameTextField.tag = index
cell.lessonNameTextField.delegate = self
cell.backgroundColor = ColorHelper.getCellBackgroundColor()
return cell
}
return UITableViewCell()
}
}
I have 11 cells and someone are missing, When i scrolled table view index returns like this;
0-1-2-3-4-5-6-7-8-0-1-2..
After reload process, my values are confused. Wrong value in wrong cell, how can i fix this ?
Your problem could possible be how many cells you are returning. Especially, if you are having problems with the last one or two. From what you said, it sounds like you have 11 cells, make sure you return 12. The cells in a UITableView always start counting with 0 being the first cell and 10 being that last cell, in your case.
func tableView(tableView: UITableView, numberOfRowsInSection section:Int) -> Int {
return 12
}

Prevent reuse of custom cells in table view Swift

I have a problem which i'm not sure how to solve.
I have two custom cell nibs - data for both is fetched from separate arrays.
The structure is the following
nib1-cell line1
nib1-cell line2
...
nib1-cell line n
nib2-cell line1
there is always one nib2-cell at the end with the uibutton.
Once the uibutton is pressed - the nib1 array is appended.
I figured out a way how to insert values at the bottom of the tableview, but when i scroll downwards or upwards the cell with nib2 is reused and replaced with nib1-cell data.
How can i either prevent those cells from being reused or save their state ?
Thank you.
UPDATE: datasource and cellForRowAtIndexPath code
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return someTagsArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if(indexPath.row < someTagsArray.count - 1){
var cell:TblCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! TblCell
cell.lblCarName.text = someTagsArray[indexPath.row]
return cell
} else if (indexPath.row == someTagsArray.count - 1){
var celle:vwAnswers = self.tableView.dequeueReusableCellWithIdentifier("cell2") as! vwAnswers
celle.Answer1.setTitle(answersdict[answersdict.endIndex - 2], forState:UIControlState.Normal)
answertitle1 = "\(celle.Answer1.currentTitle!)"
celle.Answer2.setTitle(answersdict.last, forState:UIControlState.Normal)
answertitle2 = "\(celle.Answer2.currentTitle!)"
//println(answertitle2)
return celle
} else {
var cell2:TblCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! TblCell
return cell2
}
}
You have to determine which type of cell you want in cellForRowAtIndexPath and dequeue the correct reusable cell. Maybe something like if (indexPath.row + 1)%3 == 0 then dequeue an answer cell.
However, you may possibly want to look in to using a section header for this instead. Hard to say without seeing how you implement your data source.

Resources