Uitableview - Multiple Selection and Single Selection

uitableview with single selection and multiple selection

You might have something like this in your class FilterTableViewCell (maybe next time just share more code):

override func setSelected(_ selected: Bool, animated: Bool) {
if selected {
self.accessoryType = .checkmark
}
else {
self.accessoryType = .none
}
}

So, even though your rows in section 3 have accessoryType = .none, when you select them this property is modified again.

The quick solution is to use these functions to handle the checkmark instead of setSelected:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

}

Single and Multiple Selection in same tableView

To do what you want you need to maintain the state of selection of your cell, for single selection Section declare one instance property of type IndexPath? and for multiple selection section declare one instance property of type [IndexPath]. After that compare this property in cellForRowAt method and change its value in didSelectRowAt method.

Edit: With Custom Object you can try like this way, With your sectionItem Class create one property selected of type Bool and use that to select multiple or single item

SO your class should be look like this.

class Section {
var isMultiple: Bool
var title: String
var items: [Item]

init(isMultiple: Bool, title: String, items: [Item]) {
self.isMultiple = isMultiple
self.title = title
self.items = items
}
}

class Item {
var id: Int
var name: String
//To maintain selected state
var selected: Bool = false

init(id: Int, name: String) {
self.id = id
self.name = name
}
}

Now with cellForRowAt and didSelectRowAt it should goes like this way.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
let item = sections[indexPath.section].items[indexPath.row]
if sections[indexPath.section].isMultiple {
//For multiple selection
if item.selected {
cell.accessoryType = .checkmark //Or make label red
}
else {
cell.accessoryType = .none //Or make label white
}
}
else {
//For single selection
if item.selected {
cell.accessoryType = .checkmark //Or make label red
}
else {
cell.accessoryType = .none //Or make label white
}
}
cell.textLabel?.text = sections[indexPath.section].items[indexPath.row].name

return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if sections[indexPath.section].isMultiple {
//For multiple selection
let item = sections[indexPath.section].items[indexPath.row]
item.selected = !item.selected
sections[indexPath.section].items[indexPath.row] = item
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
else {
//For multiple selection
let items = sections[indexPath.section].items

if let selectedItemIndex = items.indices.first(where: { items[$0].selected }) {
sections[indexPath.section].items[selectedItemIndex].selected = false
if selectedItemIndex != indexPath.row {
sections[indexPath.section].items[indexPath.row].selected = true
}
}
else {
sections[indexPath.section].items[indexPath.row].selected = true
}
self.tableView.reloadSections([indexPath.section], with: .automatic)
}
}

UITableView - Multiple selection AND single selection

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:

  1. Return false from tableView(_:shouldHighlightRowAtIndexPath:), and
  2. 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).

Swift make select/unselect in single/multiple selection mode for UICollectionView inside UITableViewCell

try this and let me know if you have any problem or if this solved your problem.


var arrSelectedIndex:[IndexPath] = []// store this array either in database by api or in local
var clvData:[String] = []// your data array

//get the arrSelectedIndex from default in viewDidLoad before reloading the table and collection.
override func viewDidLoad() {
super.viewDidLoad()
if let myArray = UserDefaults.standard.array(forKey: "selectedArray") as? [IndexPath] {
arrSelectedIndex = myArray
} else {
arrSelectedIndex = []
}
}

// and save the arrSelectedIndex in viewWillDisappear method
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UserDefaults.standard.set(arrSelectedIndex, forKey: "selectedArray")
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return clvData.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "clvCell", for: indexPath) as! demoCollectionViewCell
cell.title.text = clvData[indexPath.item] as? String

if arrSelectedIndex.contains(indexPath) { // You need to check wether selected index array contain current index if yes then change the color
cell.backgroundColor = UIColor.red
}
else {
cell.backgroundColor = UIColor.white
}

return cell

}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = .red
if !arrSelectedIndex.contains(indexPath) {// if it does not contains the index then add it
arrSelectedIndex.append(indexPath)
}
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = .white
if let currIndex = arrSelectedIndex.firstIndex(of: indexPath) {// if it contains the index then delete from array
arrSelectedIndex.remove(at: currIndex)
}
}

How to select multiple rows from multiple section of a UITableView?

You are overriding a method on cell setSelected while you should be implementing a delegate method didSelectRowAt. You can also get selected index paths at any time from table view by using indexPathsForSelectedRows.

There is a setting to have exclusive row selection or to be able to select multiple rows with allowsMultipleSelection. So make sure this one is set to YES.

Your overridden method still seems legit but I am unsure if it should work as you implemented it. As you say the method is called multiple times. For your case to work it should also be called when you scroll through the table view. The reason for that is that your cells are being dequeued (it is how table view works) which means a same cell will be used for multiple rows; when you scroll down a cell that will disappear on top will in fact appear on bottom as reused. Your cellForRowAtIndexPath will be called so it might be you will need to change your icon there.

UITableView with multiple sections and custom section header with single cell selection and multiple cell selection

Create an int and array of of int instance properties to store selected row details.

var selectedOfferIndex: Int? // section 0
var selectedItemIndices: [Int] = []//section 1

In cellForRowAt compare the selected values and change UI

if section == 0 {
if indexPath.row == selectedOfferIndex {
//...
} else {
//...
}
} else {//section 1
if selectedItemIndices.contains(indexPath.item) {
//...
} else {
//...
}
}

In didSelectRowAt method update the selected values

if section == 0 {
selectedOfferIndex = indexPath.row
} else {//section 1
if index = selectedItemIndices.firstIndex(of: indexPath.row) {
selectedItemIndices.remove(at: index)
} else {
selectedItemIndices.append(indexPath.row)
}
}
tableView.reloadData()


Related Topics



Leave a reply



Submit