tableviewcell repeating uibuttons - ios

I am having a little trouble with buttons on a tableview.
I have a tableViewCell that I customised with 3 buttons. I set the buttons to hidden in interface builder and when the table loads the buttons are hidden as expected.
I then set the hidden property of the tableview to false when didSelectRow is called and hidden.true when didDeselectRow is called. This works fine as well. The problem is the buttons that are set to visible in the didSelectRow are also visible every seven cells down. they keep repeating themselves.
Below is the code that shows the buttons
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ContactsViewCell
print("Table selected")
cell.insertEmailButton.hidden = false
cell.insertPhoneButton.hidden = false
cell.insertAllButton.hidden = false
cell.contactTextLabel.alpha = 0.2
cell.contactDetailTextLabel.alpha = 0.2
}
And this hides them when the tableViewCell is deselected
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ContactsViewCell
cell.insertEmailButton.hidden = true
cell.insertPhoneButton.hidden = true
cell.insertAllButton.hidden = true
cell.contactTextLabel.alpha = 1.0
cell.contactDetailTextLabel.alpha = 1.0
}
I did some research and I learnt it might be the row with the buttons.hidden set to false are being reused by the tableview. But I understand from documentation that the cell being reused is from cellForRowAtIndexPath and not the cell at didSelectRow which is where I am setting the button.hidden to false.
I also tried using the cell.isSelected property in an if else statement in the cellForRowAtIndexPath to hide and show the buttons but this does not show the buttons at all.
Thanks in advance for your help

The tableview reuses the view of the cell when the table is scrolled, to save memory. So, for example, when you set the button to visible (inside didSelectRow) and then scroll down the table, the tableview will take the cells that go out of the visible screen at the top and will reuse them at the bottom, to save the overhead of creating new cells, improving performance.
That is why, your previous properties on the cells are repeating.
To get the desired hidden button on scrolled cells, I recommend setting button.hidden to true/false in
tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
This will set the button to hidden whenever a new row is scrolled into the visible view area.
Hope this helps.

I solved the recurring buttons by hiding them when I check if the cell is deselected in cellForRowAtIndexPath. This also means any cell I select will lose its selected status and buttons will disappear when it leaves the view.
I can live with that.
if cell.selected == false{
cell.emailButton.hidden = true
cell.phoneButton.hidden = true
cell.allButton.hidden = true
}

UITableView reuses its cell to improve performance. So, you can not do the way you are trying. What we have to do is, like other tableview cell info e.g. title, description, thumb image etc we also need to save the state for buttons in the array. When you want to hide a button for the cell take object at index from the array and change the button state for the button and reload that table view cell. Still if you face problem or feel difficult to understand, please feel free to ask.

Related

UITableViewCell styling resetting when scrolled off and back onto view

I currently have a TableView in my project, which is set up to turn a cell green when it is pressed, and back to clear if it is pressed a second time. However, if I scroll down to the bottom of the table view, and scroll back up, all my cells have been reset to their default clear colour.
I'm not sure how to go about fixing this issue, as anything I can find referring to it is in Objective-C rather than Swift. Any help and advice as to how to go about this would be great, thanks.
Everytime a UITableViewCell goes out of the screen, any function that you've written in the tableViewController/ViewController runs again.
for example in cellForRowAtIndexPath if you have a cell.setUpCell() or something similar, it will rerun and reset your values to the original values.
if you have a
var name = testName in your MainVC
and you update something in your cell, you should change the name in your mainVc too.
Every time you scroll or call tableView.reloadData() UITableView cells will reload. So, every time you select UITableViewCell, add selected index (indexPath.row) to an array(ex: selectedIndexArray) in your didSelectRowAt indexPath: delegate. If the cell you selected is already selected one, then remove the cell from selectedIndexArray.
And in your cellForRowAt indexPath: manage the cells using selectedIndexArray.
var selectedIndexArray:[Int] = [] //to save selected tableViewCells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let isSelected = false
for each in selectedIndexArray
{
if each == indexPath.row
{
isSelected = true
}
}
if isSelected == true
{
//set selected cell color
}
else
{
//set default cell color
}
}
You need to write the logic of adding and removing cell indexes in your didSelectRowAt indexPath:.

How to set the background color of selected row in tableview which is child tableview?

I have a tableview which is inside the a tableview cell.
After click the "JAVA" inside "test1", I click the "About" Row which don't have the tableview inside:
But you can see that, the "About" and "JAVA" have the background colour at the same time. This is the automatic feature of tableview in iOS, I don't know how to code to prevent this happen. What I want is that when I click the "Java" inside "test1", the background color of "About" would disappear.
You are going to need to keep track of which cell was selected if you only want one cell selected at a time from both table views.
The best way to do that is to create a delegate for the nested tableview. So when that cell is selected it can call back to the parent tableview and let it know to unselect anything that was selected. The main class will need to keep track of the index that was selected as if another one is chosen then it can reach into the cell with selected cell and deselect that.
A little tricky, are you sure you can't get the same results from just using one tableview and multiple sections?
Use this code it helps you
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor.greyColor()
}
To deselect the selected row use this code
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
var cellToDeSelect:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cellToDeSelect.contentView.backgroundColor = colorForCellUnselected
}

Button in (static) cell disappears when clicking on the cell itself instead of the button

i'm having a weird issue with the code on my (static) cells. In multiple cells I have a UIButton. When I click on it, it's all fine, but when I click on the area next to the button (still in the cell itself) it turns grey (color when selected cell) + the button also disappears!
I tried to change the background of the cell to white when pressed with the following code:
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let myBackView=UIView(frame:cell.frame)
myBackView.backgroundColor = UIColor.clearColor()
cell.selectedBackgroundView = myBackView
}
but the issue is still there.
This is when the static cell isn't pushed
This is when I pressed the cell (NOT the button within the cell)
This is a common issue when selecting UITableViewCells, see Why do all backgrounds disappear on UITableViewCell select?
If you don't intend the cell to be selected, implement this delegate method:
- (NSIndexPath * _Nullable)tableView:(UITableView * _Nonnull)tableView willSelectRowAtIndexPath:(NSIndexPath * _Nonnull)indexPath
and return nil when indexPath is the one of your cell. This will disable selection for this cell.
If none of your cells is intended to be selected, it's even easier, just set your UITableView's allowsSelection to NO (this can also be done in Interface Builder).

Why do UITableView actions only work on visible cells

I'm working with a UITableView which is a list of friends (I have 20 friends). I have, on top of those 20 friends cells, a unique cell in another section called "ALL FRIENDS" which allows me to select all my friends in one click.
When this "ALL FRIENDS" cell is selected, this code is called :
var index = 0
for friend in self.friendsList {
var indexPath = NSIndexPath(forRow: index, inSection: 1)
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.None)
index += 1
}
Everything works fine for the visible cells. When a cell is selected the background color changes but this only works for visible cells.
Any ideas why ?
Because UITableView is dynamically displayed and invisible cells are not there.
UITableView basically dequeues a cell that's about to disappear and appends it where you're scrolling. To select all of the cells, you have to do it differently:
You'll have to set a global variable to true, let's say var allSelected = true.
Then call self.tableView.reloadData()
Which will be reflected in tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell by doing cell.selected = true.
That will ensure that all of the future displayed cells will be selected as well.
So Michal's answer is great, but I would like to give you an alternative: you can create that tableview without dequeuing and reusing cells, so the cells remain alive at all points.
You can do this by creating individual cells, and adding them to an array
var array = [UITableViewCell]
for friend in self.friendsList {
var cell = UITableViewCell()
// customize your cell however you want, or use custom nibs
array.append(cell)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) {
return array[indexPath.row]
}

Swift UITableView didSelectRowAtIndexPath bug

I have a UITableView with the subtitles hidden but set up where when someone selects a cell it shows that cell's subtitle. This works fine except that after tapping any cell to reveal its subtitle if you scroll down you will find that every 12 cells have their subtitle unhidden (as well as the one it was supposed to reveal). Here is the code I'm using in didSelectRowAtIndexPath:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
for cell in tableView.visibleCells() {
cell.detailTextLabel??.hidden = true
}
var cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.detailTextLabel?.hidden = false
}
I'm sure this is related to ".visibleCells()" since every 12 cells is about the height of my visible table on my iPhone 6 Plus. When I run it on a 4s in the simulator it's about every 8 cells. But I'm not sure how else to do it besides 'visibleCells'? But it's strange because it's the whole table - all the way down, every 12 cells is showing its subtitle...
thanks for any help
UITableView reuses its cells. So the cell for row a row you clicked on (unhidden the subtitle) may be used for row another row.
The solution is to define prepareForReuse() method in the UITableViewCell subclass (or make the subclass if you do not have one) and hide the subtitle again there.
Add that dataSource's method to your controller. Should work fine.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) {
var identifier = "cellIdentifier"
var cell = tableView. dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath)
cell.detailTextLabel?.hidden = true
return cell
}

Resources