UiTableViewCell single selected checkmark for each section in the tableview - ios

How to make checkmark single selection to Each Section , with custom cells , when I realize this code , cell doesn't marked
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let it = PayMentSection(rawValue: indexPath.section) else {return}
switch it {
case .delivering:
let cell = tableView.dequeueReusableCell(withIdentifier: cellid) as! MakePaymentTableViewCell
cell.checkBox.isChecked = true
cell.accessoryType = .checkmark
case .ordering:
let cell2 = tableView.dequeueReusableCell(withIdentifier: cellid2) as! MakePaymentTableViewCell2
cell2.checkBox.isChecked = true
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
guard let it = PayMentSection(rawValue: indexPath.section) else {return}
switch it {
case .delivering:
let cell = tableView.dequeueReusableCell(withIdentifier: cellid) as! MakePaymentTableViewCell
cell.checkBox.isChecked = false
cell.accessoryType = .none
case .ordering:
let cell2 = tableView.dequeueReusableCell(withIdentifier: cellid2) as! MakePaymentTableViewCell2
cell2.checkBox.isChecked = false
cell2.accessoryType = .none
}
}

First of all, implement UITableViewDelegate's tableView(_:willSelectRowAt:) method like so,
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if let selectedIndexPathsInSection = tableView.indexPathsForSelectedRows?.filter({ $0.section == indexPath.section }), !selectedIndexPathsInSection.isEmpty {
selectedIndexPathsInSection.forEach({ tableView.deselectRow(at: $0, animated: false) })
}
return indexPath
}
Next, in both MakePaymentTableViewCell and MakePaymentTableViewCell2 cells, override setSelected(_:animated:) method, i.e.
class MakePaymentTableViewCell: UITableViewCell {
//rest of the code...
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.accessoryType = selected ? .checkmark : .none
self.checkBox.isChecked = selected
}
}
There is no need to implement didSelectRowAt and didDeselectRowAt methods.

Related

TextLabel colour automatically changed when i Scroll UiTableView

I changing textlabel color on didSelectRowAt but when I scroll UITableView it also effects in other textlabel also
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
if (cell.LBLIntrest.textColor == (UIColor.black))
{
cell.LBLIntrest.textColor = Uicolor.blue
} else {
cell.LBLIntrest.textColor = Uicolor.black
}
}
First you have to create property to hold selected cell like below
/* To hold selected cell */
var selectedIndexPath :IndexPath?
After that set color of selected cell in cellForRowAt
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") {
cell.textLabel?.text = "Row Number: \(indexPath.row)"
/* Check if cell is selected then set layout accourding to your requirements */
if indexPath == selectedIndexPath {
cell.textLabel?.textColor = .blue
} else {
cell.textLabel?.textColor = .black
}
return cell
}
return UITableViewCell()
}
After this manage when user select a cell in didSelectRowAt
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Toggle if user seleted same cell
if selectedIndexPath == indexPath {
if let cell = tableView.cellForRow(at: indexPath) {
/* Check and toggle selected cell color */
cell.textLabel?.textColor = cell.textLabel?.textColor == .black ? .blue : .black
}
} else {
/* set color of seleted cell */
if let cell = tableView.cellForRow(at: indexPath) {
cell.textLabel?.textColor = .blue
}
}
/* Save which cell is selected */
selectedIndexPath = indexPath
}
And last manage didDeselectRowAt
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
/* Remove if deselect same cell */
if selectedIndexPath == indexPath {
selectedIndexPath = nil
}
/* Change color to black */
if let cell = tableView.cellForRow(at: indexPath) {
cell.textLabel?.textColor = .black
}
}
This code is for on cell selection at one time so you have to set
tableView.allowsMultipleSelection = false
Hope this helps.
This should work for you.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
setSelectedColor(cell: cell)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
...
if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
setSelectedColor(cell: cell)
}
return cell
}
func setSelectedColor(cell: UITableViewCell) {
if (cell.LBLIntrest.textColor == (UIColor.black)) {
cell.LBLIntrest.textColor = Uicolor.blue
} else {
cell.LBLIntrest.textColor = Uicolor.black
}
}
But, I would recommend moving that cell.LBLIntrest.textColor = Uicolor.blue to UITableViewCell under func setSelected(_ selected: Bool, animated: Bool) method
class TableViewCell: UITableViewCell {
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// label textColor logic goes here
// make use of selected
}
}

Multiple Cell Selection on TableView

I'm having an issue where when I'm selecting the cell for e.g at index 3 , it selecting cells below also at random indexes. Check and Uncheck cell is working but for some reasons when selecting a cell it is selecting other cells as well. My array is returning 120 rows in total. I have selected multiple touch. Thank you for the help.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return arrayVerbCount.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell
cell.verb!.text = arrayVerbCount[indexPath.row].verb
if cell.isSelected
{
cell.isSelected = false
if cell.accessoryType == UITableViewCellAccessoryType.none
{
cell.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.none
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
if cell!.isSelected
{
cell!.isSelected = false
if cell!.accessoryType == UITableViewCellAccessoryType.none
{
cell!.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell!.accessoryType = UITableViewCellAccessoryType.none
}
}
}
My custom cell class:
class MesTalentsChoixCell: UITableViewCell {
#IBOutlet weak var verb: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
You should do like this way, this is very much easy solution if there is only one section.
Initialize selectedItems array like this,
var selectedItems: [Int] = []
Find UITableViewDataSource method below
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
cell.tmpValue.text = data[indexPath.row]
if selectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
Find UITableViewDelegate Method below.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if selectedItems.contains(indexPath.row) {
let index = selectedItems.index(of: indexPath.row)
selectedItems.remove(at: index!)
} else {
selectedItems.append(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
Code will be changed depending on your requirement and custom cell. Hope you can do it your way. Thank you.
UPDATE
You can even use Set also like this way,
var setSelectedItems: Set<Int> = []
UITableViewDataSource method,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! CustomCell
cell.tmpValue.text = data[indexPath.row]
if setSelectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
} else {
cell.accessoryType = .none
}
return cell
}
UITableViewDelegate method,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if setSelectedItems.contains(indexPath.row) {
setSelectedItems.remove(indexPath.row)
} else {
setSelectedItems.insert(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
}
Make bool array for stability while scrolling i.e.
var arrStatusBool = [Bool]()
Now set value at indexPath.row in didSelectRowAt
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if self.arrStatusBool[indexPath.row]
{
self.arrStatusBool[indexPath.row] = false
}
else
{
self.arrStatusBool[indexPath.row] = true
}
}
And also put this in cellForRowAt to avoid scrolling issue.
if self.arrStatusBool[indexPath.row]
{
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
else
{
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
hope this help!
For multiple selection you should track selected cells in a Dictionary for convenience faster access to selected and unselected indexPaths allowing you use multiple sections because the key value of our Dictionary is a string formed by (IndexPath.section)+(IndexPath.row) which is always unique combination
var selectedIndexPaths : [String:Bool] = [:]
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
self.selectedIndexPaths[currentIndexPathStr] = true
}else{
self.selectedIndexPaths[currentIndexPathStr] = false
}
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "npCell", for: indexPath) as! NewPlaylistTableViewCell
cell.mTitle.text = musics[indexPath.row]["title"] as! String?
cell.mArtist.text = musics[indexPath.row]["artist"] as! String?
cell.accessoryType = .checkmark
let currentIndexPathStr = "\(indexPath.section)\(indexPath.row)"
if(self.selectedIndexPaths[currentIndexPathStr] == nil || !self.selectedIndexPaths[currentIndexPathStr]!) {
cell.accessoryType = .none
}
return cell
}
Results
Just a minor change
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MesTalentsChoixCell
cell.verb!.text = arrayVerbCount[indexPath.row].verb
if cell.isSelected
{
cell.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell.accessoryType = UITableViewCellAccessoryType.none
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let cell = tableView.cellForRow(at: indexPath)
//toggle the state
cell!.isSelected = !cell!.isSelected
if cell!.isSelected
{
cell!.accessoryType = UITableViewCellAccessoryType.checkmark
}
else
{
cell!.accessoryType = UITableViewCellAccessoryType.none
}
}
Note: you should also create method for common code :-)

Unable to Display Check Mark in Particular row in TableView and want to set a checkmark in a UITableView first time the table is loaded with data?

I am new to coding, I have a mutable array that contains nearly 20 names and I loaded that in a table view. I want to show checkmark for a particular name row in table view based on ID but am unable to do that. Please help to fix that issue.
Here I give the code what I am tried.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == productListTableView {
let cell:BillTableViewCell = tableView.dequeueReusableCell(withIdentifier: "BillTableViewCell") as! BillTableViewCell
let productName:String = (productNameArray[indexPath.row] as? String)!
cell.productNameLbl.text = productName
print("addIdsMutArray :",addIdsMutArray)
print(addIdsMutArray.count)
print("oldSelectedIDStr :",oldSelectedIDStr)
for i in (0..<addIdsMutArray.count)
{ var arrayCheck = NSArray()
arrayCheck = addIdsMutArray[i] as! NSArray
print(self.addIdsMutArray)
if arrayCheck.contains(oldSelectedIDStr)
{
print("Found")
cell.accessoryType = .checkmark
tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.bottom)
} else {
print("Not Found")
cell.accessoryType = .none
}
}return cell}
The problem is the loop, here the solution:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == productListTableView {
let cell:BillTableViewCell = tableView.dequeueReusableCell(withIdentifier: "BillTableViewCell") as! BillTableViewCell
let productName:String = (productNameArray[indexPath.row] as? String)!
cell.productNameLbl.text = productName
print("addIdsMutArray :",addIdsMutArray)
print(addIdsMutArray.count)
print("oldSelectedIDStr :",oldSelectedIDStr)
//set not check for default
cell.accessoryType = .none
for i in (0..<addIdsMutArray.count)
{ var arrayCheck = NSArray()
arrayCheck = addIdsMutArray[i] as! NSArray
print(self.addIdsMutArray)
if arrayCheck.contains(oldSelectedIDStr)
{
print("Found")
cell.accessoryType = .checkmark
tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.bottom)
break;
}
}
return cell
}
Consider this generic code that shows checkmark in every alternate cell. Edit the if condition to match yours.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
if indexPath.row % 2 == 0{
cell.accessoryType = .checkmark
}else{
cell.accessoryType = .none
}
cell.textLabel?.text = dummyData[indexPath.row]
return cell
}
This is how it looks:
The only difference is the lack of your call to selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.bottom).
I'm not sure why this is done, but understand that at the end of the loop only the last matched cell will be selected.

UItableview on one click multiple cell are getting checked swift 3

I am having a problem in uitableview whenever I select one cell 4th no cell auto get selected... I am tired of this problem someone please help here is my didselectrowfunc..
////////////////For Adding Check Box////////////////////////
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.cellForRow(at: indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark
{
if selectedDisease.count > 0
{
let no = selectedDisease.index(of: finall[indexPath.row])
selectedDisease.remove(at: no!)
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
print(selectedDisease)
}
else
{
selectedDisease = [""]
}
}
else
{
if selectedDisease.contains("")
{
selectedDisease.removeAll()
var name = finall[indexPath.row]
selectedDisease.append(name)
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
print(selectedDisease)
}
else
{
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
selectedDisease.append(finall[indexPath.row])
//selectedDisease = [finall[indexPath.row]]
print(selectedDisease)
}
}
}
/////////CellForRowAt///////////////
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "diseasetable", for: indexPath) as! FoodTableViewCell
cell.DiseaseName.text = finall[indexPath.row]
//indexsave.append(indexPath.row)
return cell
}
Try this logic hope this will solve your problem
let dict = [NSIndexPath: String]()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
if let _ = // dict contains value at indexpath {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if ( // dict contains value == indexpath) {
// remove value from dict
} else {
//add value to dict
}
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
Just take the advantage of prepareForReuse method of UITableViewCell. In your FoodTableViewCell class implement the prepareForReuse menthod like following
class FoodTableViewCell: UITableViewCell
{
override func awakeFromNib()
{
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse()
{
self.accessoryType = UITableViewCellAccessoryType.none
//add code to reset selection if there is any other selection mechanism
}
}

indexPathForSelectedRow returns nil although I have a cell programmatically selected

I have a UITableView which I load with some application settings. I need the table to be single-select, and since the table holds settings there might be a chance some cell will be programmatically selected based on the setting enabled status.
Currently, I'm experiencing a weird behaviour where if I programmatically select a cell then indexPathForSelectedRow returns nil (when it should return the index for the cell I selected), thus when I tap on a second cell (to change the currenty selected setting) I end up with two cells selected (even when I set allowMultipleSelection to false in my tableView object).
Here's my code:
override func viewDidLoad() {
tableView.allowsMultipleSelection = false
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("myCell")
if let cell = cell {
// tableObject is an array containing settings model
let row = tableObject[indexPath.row]
cell.textLabel!.text = row.settingValue
if row.selected {
cell.setSelected(true, animated: false)
cell.accessoryType = .Checkmark
}
cell.tag = row.id
}
return cell!
}
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
// oldIndex is always nil for the cell I called setSelected in cellForRowAtIndexPath
if let oldIndex = tableView.indexPathForSelectedRow {
if let oldCell = tableView.cellForRowAtIndexPath(oldIndex) {
tableView.deselectRowAtIndexPath(oldIndex, animated: true)
oldCell.accessoryType = .None
}
}
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.setSelected(true, animated: true)
cell.accessoryType = .Checkmark
}
return indexPath
}
override func tableView(tableView: UITableView, willDeselectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.accessoryType = .None
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
return indexPath
}
Any idea how I can always have only one cell selected at a time?
Thanks!
Just in case someone else comes across this same behaviour, it seems that selecting the cell through cell.setSelected() it's not the same as invoking tableView.selectRowAtIndexPath() method. Selecting the row with the latest does the job perfectly and solves the issue.
Note that calling tableView.reloadData() resets the tableView.indexPathForSelectedRow to nil.
here how you can accomplish table view single selection through tableView.indexPathForSelectedRow :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.accessoryType = tableView.indexPathForSelectedRow == indexPath ? .checkmark : .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
if let visiblePaths = tableView.indexPathsForVisibleRows
{
for visibleIndexPath in visiblePaths
{
let cell = tableView.cellForRow(at: visibleIndexPath)
if visibleIndexPath == indexPath
{
cell?.accessoryType = .checkmark
}
else
{
cell?.accessoryType = .none
}
}
}
}
Create an array like
var arrSelectCell = [NSIndexPath]()
And do the code at didSelectRowAtIndexPath like following:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if arrSelectCell.contains(indexPath) {
if let oldCell = tableView.cellForRowAtIndexPath(indexPath) {
if let index = arrSelectCell.indexOf(indexPath) {
arrSelectCell.removeAtIndex(index)
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
oldCell.accessoryType = .None
}
}
else
{
arrSelectCell.append(indexPath)
if let selectCell = tableView.cellForRowAtIndexPath(indexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
selectCell.accessoryType = .Checkmark
}
}
and also dont forget to set a code in cellForRowAtIndexPath to check already checked and unchecked cell maintain after reuse cell also. So need to few code you need to write as following.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("serchCell", forIndexPath: indexPath) as! SearchTableViewCell
if arrSelectCell.contains(indexPath)
{
cell.accessoryType = .Checkmark
}
else
{
cell.accessoryType = .None
}
return cell
}

Resources