Table view cell accessory not changing when out of view - swift

I have this piece of code:
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if let selected = self.lastSelected {
tableView.cellForRowAtIndexPath(selected)?.accessoryType = .None
}
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.Checkmark
self.lastSelected = indexPath
I allows me to place a checkmark on the cell that I select and removes the previous checkmark. The problem I am having is that if the list is large and the cell is out of view, the checkmark is not removed when a new cell is selected.
I have tried adding tableview.reloaddata() but that did nothing.
Thoughts?

cellForRowAtIndexPath returns nil for non-visible cells.
To get a radio button like effect, you need to do something like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
configureCell(cell, atIndexPath: indexPath)
return cell
}
func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
if indexPath == selectedIndexPath {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedIndexPath = indexPath
// Note indexPathsForVisibleRows may be nil depending on your app's content.
// zip just joins two arrays together, into a single array of tuples.
zip(tableView.indexPathsForVisibleRows!, tableView.visibleCells).forEach({ indexPath, cell in
configureCell(cell, atIndexPath: indexPath)
})
}

Related

How to change image in imageview when tableview cell is expand and collapse in swift

I am using two images for cell, one i am showing when tableview cell is expand and the other one when cell is collapse
when cell expand i am using arrow-bottom
when cell is collapse arrow-right
for cell expand and collapse i am using below code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let cell = tableView.cellForRow(at: indexPath) as! FAQTableVIewCell
if selectedIndex == indexPath.row{
if self.isCollapse == false{
cell.arrowImage.image = UIImage(named: "arrow-rightt")
self.isCollapse = true
}else{
cell.arrowImage.image = UIImage(named: "arrow-bottom")
self.isCollapse = false
}
}else{
self.isCollapse = true
}
self.selectedIndex = indexPath.row
tableView.reloadRows(at: [indexPath], with: .automatic)
}
but the above code not working properly, first time when i expand cell its not showing bottom arrow, and if i expand two cells then also its not showing properly, pls do help with code
i need when cell expand then i need to show bottom-arrow, when cell in normal(back to its orginal position or collapsed position) then i need to show right-arrow
When you reload rows, they get in cellForRowAt method.
You must apply changes in this method. Store collapsed indexPath and check it in method.
With array:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//use your cell identifier
let cell = tableView.dequeueReusableCell(withIdentifier: "FAQTableVIewCell", for: indexPath) as! FAQTableVIewCell
let image = collapsedCells.contains(indexPath) ? UIImage(named: "arrow-rightt") : UIImage(named: "arrow-bottom")
cell.image = image
//other settings
return cell
}
var collapsedCells = [IndexPath]()
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//use your height values instead 44 and 120
return collapsedCells.contains(indexPath) ? 44 : 120
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let index = collapsedCells.firstIndex(of: indexPath) {
collapsedCells.remove(at: index)
} else {
collapsedCells.append(indexPath)
}
tableView.reloadRows(at: [indexPath], with: .automatic)
}

How do i disable unused rows of UITableView (Swift)?

When it comes to creating a dynamic type table view in a storyboard, it automatically fills up the table with rows.
How would i disable the red lined section (unused rows yet) of the image?
Use tableView(_:cellForRowAt:) method from UITableViewDataSource, like so
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellId", for: indexPath)
if indexPath.section == DISABLED_SECTION_INDEX {
cell.isUserInteractionEnabled = false
} else {
cell.isUserInteractionEnabled = true
}
}
Or without if statement
cell.isUserInteractionEnabled = indexPath.section != DISABLED_SECTION_INDEX

Deselect cell only if other cell in section is tapped

I have a table view with two sections. Each cell in section 1 (the second section) has a tap accessory and a deselect method for when another cell in section 1 is tapped. However, if any cell in section 0 is tapped this also deselects the current selected cell.
My code is:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if(indexPath.section == 1)
{
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
}
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
if(indexPath.section == 1)
{
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .None
}
}
I would only like the cells to be deselected if any other cell in section 1 is selected and ignore deselect for any other section.
Any thoughts?
For proper Reference, you need manage the reference in your globalArray itself, as shown below:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
.........
if ( globalArray[indexpath.row][SELECTED_STATE] == SELECTED )
{
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
}
else
{
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .None
}
.........
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//remove the pre selected state if needed by iterating the array
globalArray[indexpath.row][SELECTED_STATE] = SELECTED
tableView .reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
}

how to add checkmark in tableview swift

I'm trying to show checkmark on tableview cell, but the checkmark appears only sometimes and it disappears when I scroll.
Below the code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("vvxxx12", forIndexPath: indexPath)
// Configure the cell...
cell.textLabel?.text = self.dataArray[indexPath.row] as? String //in dataArray values are stored
if dataArray.containsObject(indexPath)
{
cell.accessoryType = .Checkmark
}
else {
cell.accessoryType = .None
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
if cell.accessoryType == .Checkmark {
cell.accessoryType = .None
} else {
cell.accessoryType = .Checkmark
}
}
}
Just do following changes in your code to maintain checkmark into tableview while you are scrolling tableview
Result :
Its work fine now, Any problem let me know i will definitely help you to out.Enjoy..
For Swift 3 following worked for me to
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
yourtableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
yourtableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .none
}
cell.textLabel?.text = self.dataArray[indexPath.row] as? String
This suggests that dataArray contains strings.
if dataArray.containsObject(indexPath)
This suggests that dataArray contains index paths. Both of these should not be true. One array for data makes sense, and another one for selected rows or rows to be checked also makes sense, but not the same array for both.
What's probably happening is:
Row selected - cell is then updated to have the checkmark accessory
Table scrolled and cellForRowAtIndexPath is called - at no point will dataArray contain an index path, so the accessory is always cleared.
You need to be updating your model when a row is selected, to store the index path of the selected row, or update a selected flag on your model objects.

UITableView - Multiple selection AND single selection

I have 2 sections in my UITableView.
I want the first section to allow multiple cell selection and the second section to allow only single selection.
I tried some code but didn't work very well.
Code in swift if possible. Thank you.
You can simply try this. This solution works for me perfectly. Give it a try maybe worked for others...
Swift-4
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
}
else {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
}
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if indexPath.section == 1 {
if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
cell.accessoryType = .none
}
}
}
Perhaps you could implement the table view's delegate methods:
tableView(_:shouldHighlightRowAtIndexPath:)
and
tableView(_:didSelectRowAtIndexPath:)
...and determine (from indexPath.row and indexPath.section) if the relevant section supports single/multiple selection (this will depend on your data model's custom logic -e.g.: "Section 0 supports multiple selection but section 1 does not"), and if it only supports single selection, check whether there is already a row selected (by accessing tableView.indexPathsForSelectedRows).
If there is a selected row already, you can:
Return false from tableView(_:shouldHighlightRowAtIndexPath:), and
Do nothing (just return) from tableView(_:didSelectRowAtIndexPath:) (I'm not sure if this method is actually called when you return false from shouldHighlight..., so perhaps check it).
This is easily achievable in two lines as follows: (Swift 4)
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if sectionAllowsMultipleSelection {
if let indexPathsInSection = tableView.indexPathsForSelectedRows?.filter ({ $0.section == indexPath.section && $0.row != indexPath.row }) {
for selectedPath in indexPathsInSection {
tableView.deselectRow(at: selectedPath, animated: false)
}
}
}
}
If you want the selected row in section 2 to be the new selected row, this might work for you. Else, go with #NicolasMiari's answer.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 1 {
for i in 0..tableView.numberOfRowsInSection(indexPath.section) - 1 {
let cell: UITableViewCell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: i, inSection: indexPath.section))!
if (i == indexPath.row) {
cell.accessoryType = .Checkmark
cell.selected = false
}
else {
cell.accessoryType = .None
}
}
}
else {
//Do whatever for the first section
}
}
Not very elegant, but hopefully it will give you an idea.