Dima Bonderzev
Dima Bonderzev

Reputation: 21

Swift Every time I scroll in tableView the cells that been selected are getting unselected

*hi I have a problem if anyone can guide me to the appropriate solution for this one it will be awesome.... I have a tableview with list items that can be selected (like a checkbox) also a textview that when I write there I don't won't the text deleted (for the user) every time It scrolls. my custom cell class - >

class ReportIssueTableViewCell: UITableViewCell, ReusableView, NibLoadableView {
    
    //MARK: Properties
    @IBOutlet private weak var lblTitleIssue: UILabel!
    @IBOutlet private weak var imgCircleCheck: UIImageView!
    @IBOutlet private weak var textView: WSTextView!
    @IBOutlet private weak var stackView: UIStackView!
    @IBOutlet private weak var sepratorView: UIView!
    
    private var reportIssue: ReportIssue?
    private var textContent = ""
    private var lastIndex = false
    
    //MARK: Methods
    func setupDataForCell(isSelected: Bool, reportIssues: ReportIssue, lastIndex: Bool) {
        self.isSelected = isSelected
        self.reportIssue = reportIssues
        self.lastIndex = lastIndex
        updateUI()
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        textView.text = textContent
        imgCircleCheck.image = nil
    }
    func updateUI() {
        guard let reportIssue = reportIssue else { return }
        lblTitleIssue.text = reportIssue.name
        updateImageUI()
        updateTextView()
        updateTitleUI()
    }
    
    func sepratorView(hide: Bool, lastIndex: Bool) {
        sepratorView.isHidden = (lastIndex && hide)
    }
    
    //MARK: Private Methods
    private func updateTitleUI() {
        let font = lblTitleIssue.font.pointSize
        lblTitleIssue.font = isSelected ? SharedFonts.latoBold.ofSize(font) : SharedFonts.latoRegular.ofSize(font)
    }
    
    private func updateImageUI() {
        imgCircleCheck.image = isSelected ? R.image.iconCircleCheckFull() : SharedAssets.iconsCircle()
    }
    
    private func updateTextView() {
        textView.isHidden = !(lastIndex && isSelected)
    }
    
}

also my view controller class and the tableview delegate & data source...

extension ReportIssueViewController: UITableViewDelegate , UITableViewDataSource {

func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
    if section == 0 {
        let footerView = UIView()
        footerView.backgroundColor = SharedColors.woodspoon_extra_light_gray()
        return footerView
    }else {
        return UIView()
    }
}

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
    return 8
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    guard let name = viewModel.reportTopics?[section].name else { return nil }
    let header = SectionTitleHeaderView(textDescriptor: .init(text: name, appearance: .init(color: SharedColors.woodspoon_black(), font: SharedFonts.latoBlack.ofSize(18))))
    return header
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if #available(iOS 15.0, *) {
        tableView.sectionHeaderTopPadding = 0
    } else {
        //Fallback on earlier versions
    }
    return UITableView.automaticDimension
}

func numberOfSections(in tableView: UITableView) -> Int {
    return viewModel.reportTopics?.count ?? 0
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return viewModel.reportTopics?[section].reportIssues?.count ?? 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: ReportIssueTableViewCell = tableView.dequeueReusableCell(for: indexPath)
    
    if let issue = viewModel.reportTopics?[indexPath.section].reportIssues?[indexPath.row] {
        let countIssues = viewModel.reportTopics?[indexPath.section].reportIssues?.count ?? 0
        let lastIssue = countIssues - 1 == indexPath.row
        let isSelected = tableView.indexPathsForSelectedRows?.contains(where: { $0.section == indexPath.section && $0.row == indexPath.row })
        //remove seperator from last cell in each section
        if isSelected == isSelected {
            cell.sepratorView(hide: true ,lastIndex: lastIssue)
        }
        cell.setupDataForCell(isSelected: isSelected ?? false, reportIssues: issue, lastIndex: lastIssue)
    }
    return cell
}

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

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

private func cellPressed(indexPath: IndexPath) {
    guard let cell = tableView.cellForRow(at: indexPath) as? ReportIssueTableViewCell else { return }
    tableView.beginUpdates()
    cell.updateUI()
    tableView.endUpdates()
}*

Upvotes: 1

Views: 987

Answers (1)

ygam
ygam

Reputation: 131

I think it happens because the reuse of cells.

Your problem starts here:

 isSelected = tableView.indexPathsForSelectedRows?.contains(where: { 
      $0.section == indexPath.section && $0.row == indexPath.row 
 })

Add an isSelected value to the model used to populate the cell and get it from your viewModel by adding an isSelected func that return bool value and get it inside cellForRowAt IndexPath.

Something like this:

 func isSelected(by indexPath: IndexPath) { }

And remember to update the model (via viewModel) when a cell was selected.

Upvotes: 1

Related Questions