Как сделать так, чтобы значки галочек (вспомогательный вид) на табличном виде уже проверялись после визуализации ячеек? - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть данные модели, которые имеют логическое значение, которое говорит, что если должна отображаться галочка (accessoryType is .checkmark) ...

Так, например, я хочу, чтобы две или пять строк отмечались галочкой в ​​начале(основываясь на моей модели, как я уже сказал) ... Дело в том, что я могу показывать галочки, но после нажатия на них переключение не работает правильно:

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

    if let cell = tableView.cellForRow(at: indexPath) {
        cell.accessoryType = .checkmark
        model[indexPath.row].isCellSelected = true


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

    if let cell = tableView.cellForRow(at: indexPath) {
        cell.accessoryType = .none
        model[indexPath.row].isCellSelected = false


    }
}

And here is a cellForRowAt:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let data = model[indexPath.row]
    let identifier = data.subtitle != nil ? kSubtitleID : kNormalID

    let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)

    cell.textLabel?.text = data.title
    cell.detailTextLabel?.text = data.subtitle

    return cell
}

Я могупокажите галочку вот так:

cell.accessoryType = data.isCellSelected ? .checkmark : .none

Но когда я нажимаю на нее, это происходит потому, что она выбрана (для параметра allowMultipleSelection установлено значение true), она не переключается, а остается в первый раз.

Вот модель, которую я использую.Это действительно просто:

struct CellModel{
    var title:String?
    var subtitle:String?
    var isCellSelected:Bool = false
}

Ответы [ 6 ]

0 голосов
/ 13 декабря 2018

Почему бы вам не попробовать следующее?

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

    if let cell = tableView.cellForRow(at: indexPath) {
        cell.accessoryType = .none
        model[indexPath.row].isCellSelected = false
    tableView.reloadRows(at: [indexPath], with: <UITableViewRowAnimation>)
    }
}
0 голосов
/ 13 декабря 2018

@ Вихрь, Привет, это не так сложно, если вам нужно показывать выборки только внутри tableView, здесь я передаю свои ответы после обновления вашей модели.

Это можно сделать, поддерживаяisCellSelected свойство только в didSelectRowAt.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    model[indexPath.row].isCellSelected = model[indexPath.row].isCellSelected ? false : true
    tableView.reloadData()
}

Здесь cellForRowAt Вы также можете изменить еще несколько строк здесь.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let data = model[indexPath.row]
    let identifier = "kNormalID"
    let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
    cell.textLabel?.text = data.title
    cell.detailTextLabel?.text = data.subtitle
    cell.accessoryType = data.isCellSelected ? .checkmark : .none
    return cell
}

Надеюсь, я доставил тебе все возможное.Дайте мне знать, если я что-то пропустил.

0 голосов
/ 12 декабря 2018

Затем метод cellForRowAt становится таким простым, как:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let data = model[indexPath.row]
    let identifier = data.subtitle != nil ? kSubtitleID : kNormalID

    let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)

    cell.textLabel?.text = data.title
    cell.detailTextLabel?.text = data.subtitle

    cell.accessoryType = data.isCellSelected ? .checkmark : .none

    return cell
}

Затем метод didSelectRowAt становится таким простым, как:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)

    if let cell = tableView.cellForRow(at: indexPath) {        
        let isCellSelected = !(model[indexPath.row].isCellSelected)
        cell.accessoryType = isCellSelected ? .checkmark : .none
        model[indexPath.row].isCellSelected = isCellSelected
    }
}

Обратите внимание, что нам пришлось переключить флаги обновите ячейку и модель на основе нового значения.

Более того, вы можете заменить строку обновления типа .accessory на:

tableView.reloadRows(at: [indexPath], with: .none)

Таким образом, метод будет выглядеть следующим образом:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)

    if let cell = tableView.cellForRow(at: indexPath) {        
        let isCellSelected = !(model[indexPath.row].isCellSelected)
        model[indexPath.row].isCellSelected = isCellSelected
        tableView.reloadRows(at: [indexPath], with: .none)
    }
}

Обратите внимание, что мы обновляем model, затем перезагружаем ячейку, которая вызовет cellForRowAt, и этот метод заботится о правильной конфигурации на основе модели.

В более общем плане, я бы рекомендовал использовать какой-нибудь объект StateController, чтобы сохранить состояние для каждой ячейки / строки, и позаботиться о toggling.

. Недавно я написал целую статью о том, чтоделает именно то, что вам нужно, и демонстрирует множество лучших практик:

https://idevtv.com/how-to-display-a-list-of-items-in-ios-using-table-views/

0 голосов
/ 12 декабря 2018

Что я сделал, чтобы сделать всю работу:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let data = model[indexPath.row]
        if let cell = tableView.cellForRow(at: indexPath) {
            cell.accessoryType = .checkmark
            model[indexPath.row].isCellSelected = true

            self.selectedData?(model.filter{$0.isCellSelected})
        }
    }
     func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
         let data = model[indexPath.row]
        if let cell = tableView.cellForRow(at: indexPath) {
            cell.accessoryType = .none
            model[indexPath.row].isCellSelected = false

            self.selectedData?(model.filter{$0.isCellSelected})
        }
    }

и

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let data = model[indexPath.row]
        let identifier = data.subtitle != nil ? kSubtitleID : kBasicID

        let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)

        cell.textLabel?.text = data.title
        cell.detailTextLabel?.text = data.subtitle

        cell.accessoryType = data.isCellSelected ? .checkmark : .none
        return cell
    }

, но мне пришлось изначально настроить, какие ячейки выбраны на самом деле:

func setSelectedCells(){

        let selectedIndexes = self.model.enumerated().compactMap { (index, element) -> IndexPath? in
            if element.isCellSelected{
                return IndexPath(row: index, section: 0)
            }
            return nil
        }

        selectedIndexes.forEach{
            selectRow(at: $0, animated: false, scrollPosition: .none)
        }
    }

и затем вызвал это в viewDidAppear, потому что я должен был быть уверен, что таблица нарисовала свое содержимое (потому что это потерпит неудачу, если мы попробуем что-то (ячейку), которая еще не существует).Не лучшим способом, но это решило проблему для одиночных и множественных выборов с начальными состояниями .

0 голосов
/ 12 декабря 2018

Вам не нужно использовать выбор и отмена выбора, пока у вас не появится модель, которая сохраняет логическое значение. В табличном методе didselect

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

        if model[index.row].isCellSelected == true {
            model[indexpath.row].isCellSelected = false
        }
        else {
            model[indexpath.row].isCellSelected = true
        }
        tableview.reloadData

}

И в ячейке для проверки строки

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if model[index.row].isCellSelected{
        cell.accessoryType = .checkmark
    }
    else {
        cell.accessoryType = .none
    }
}
0 голосов
/ 12 декабря 2018

Вы должны выполнить переключение только в tableView:didSelectRowAt:, а затем перезагрузить необходимую ячейку.Вы должны опустить tableView:didDeselectRowAt:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) {
        // Toggle the value - true becomes false, false becomes true
        model[indexPath.row].isCellSelected = !model[indexPath.row].isCellSelected
        tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .none)
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let data = model[indexPath.row]
    let identifier = data.subtitle != nil ? kSubtitleID : kNormalID

    let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)

    cell.textLabel?.text = data.title
    cell.detailTextLabel?.text = data.subtitle
    // Set the checkmark or none depending on your model value
    cell.inputAccessoryType = data.isCellSelected ? .checkmark : .none

    return cell
}

Редактировать:

Используйте это только для одиночного выбора + возможность отменить выбор выбранного элемента:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // Loop through all model items
    for (index, item) in model.enumerated() {
        if (index == indexPath.row) {
            // Toggle tapped item
            item.isCellSelected = !item.isCellSelected
        } else {
            // Deselect all other items
            item.isCellSelected = false
        }
    }
    tableView.reloadData();
}
...