Agung
Agung

Reputation: 13883

how to make limited multiple checkmark in Table View Cell in Swift?

enter image description here

I am new in programming and iOS Development, I need to make table view that has multiple limited checkmark.

I mean, I want to allow the user to select maximum 3 items (not just 1, but also not all of item in the table view can be selected) in the table view, I have tried but I haven't gotten what I want, I just can select one only item in table view

here is the code I use

import UIKit

class CreateEventStep2VC: UIViewController {

    @IBOutlet weak var eventTypeNameLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!

    var newEvent : [String:Any]!
    var eventTypeAvailableData = [String]()
    var selectedEventTypes = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        // initial value
        eventTypeNameLabel.text = ""

        // get event Type Data list from EventType data model
        eventTypeAvailableData = EventType.allValues.map { $0.toString() }
    }




}

extension CreateEventStep2VC : UITableViewDataSource {

    //MARK: - UITableViewDatasource

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return eventTypeAvailableData.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "EventTypeCell", for: indexPath) as! CreateEventStep2Cell
        cell.eventTypeNames = eventTypeAvailableData[indexPath.row]
        return cell
    }

}


extension CreateEventStep2VC : UITableViewDelegate {

    //MARK: - UITableViewDelegate
    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) {
            cell.accessoryType = .none
        }
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) {
            cell.accessoryType = .checkmark

        }
    }



}

could you please help me ?

Upvotes: 0

Views: 821

Answers (2)

Shehata Gamal
Shehata Gamal

Reputation: 100549

You can have array of indexPath rows allArr like this

1- when user selects more than 3 the first one will be automatically dropped

var allArr = [Int]()

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

     if let cell = tableView.cellForRow(at: indexPath) {
        cell.accessoryType = .checkmark
        allArr.append(indexPath.row)
     }

     if(allArr.count == 4)
     {
         allArr.dropFirst()

     }

}

2- add this to cellForRow

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "EventTypeCell", for: indexPath) as! CreateEventStep2Cell
    cell.eventTypeNames = eventTypeAvailableData[indexPath.row]

  if allArr.contains(indexPath.row)  {
       cell.accessoryType = .checkmark
   }
   else
   {
      cell.accessoryType = .none
   }
    return cell
}

3- remove code in didSelectRowAt

Upvotes: 0

Paulw11
Paulw11

Reputation: 115076

You can't simply add the checkmark to the cell; cell objects will be re-used as the tableview scrolls, so you will lose checkmarks and end up with checkmarks in cells that shouldn't have them.

You need to track the checked cells in another structure; I suggest using a Set<IndexPath>. You can either allow multi-selection in your tableview, or (my preference) deselect the row after you add the checkmark.

You also need to ensure that your cellForRowAt: sets the accessory type correctly

class CreateEventStep2VC: UIViewController {

    @IBOutlet weak var eventTypeNameLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!

    var newEvent : [String:Any]!
    var eventTypeAvailableData = [String]()
    var selectedEventTypes = Set<IndexPath>()

    override func viewDidLoad() {
        super.viewDidLoad()

        // initial value
        eventTypeNameLabel.text = ""

        // get event Type Data list from EventType data model
        eventTypeAvailableData = EventType.allValues.map { $0.toString() }
    }

}

extension CreateEventStep2VC : UITableViewDataSource {

    //MARK: - UITableViewDatasource

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return eventTypeAvailableData.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "EventTypeCell", for: indexPath) as! CreateEventStep2Cell
        cell.eventTypeNames = eventTypeAvailableData[indexPath.row]
        cell.accessoryType = selectedEventTypes.contains(indexPath) ? .checkMark:.none

        return cell
    }

}


extension CreateEventStep2VC : UITableViewDelegate {

    //MARK: - UITableViewDelegate
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: false)
        if selectedEventTypes.contains(indexPath) {
            selectedEventTypes.remove(indexPath)
        } else if selectedEventTypes.count < 3 {
            selectedEventTypes.insert(indexPath)
        }
        tableView.reloadRows(at: [indexPath], animated:.none)
    }
}

Upvotes: 2

Related Questions