Как сохранить выбор клетки, нужна лучшая практика - PullRequest
0 голосов
/ 08 июня 2018

Ситуация

Существует табличное представление, показывающее список статей: Статья.Статья - это объект структуры, а список статей - это инициализированный ответ API.

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

cell.accessoryType = .checkmark

Проблема

Проблема

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

struct Article используется во всем приложении, поэтому мы не должен просто добавить в него поле isSelected .

struct Article {
    let title: String
    var isSelected: Bool // <- Not good.  Article used over the app.
}

временное решение

Некоторое решение, которое я использую, состоит в создании массива bool для хранениякакая строка выбрана.

var selectedRow: Bool = {
    return articles.map { return false }
}()

Но этот подход кажется странным и также уязвим для вставки и удаления ячеек.

Вопрос

Есть ли лучшее решение?


Код решения нечетного пути

import UIKit

struct Article {
    let title: String
}

class SampleTableViewController: UITableViewController {

    // MARK: - Properties

    let articles: [Article] = {
        var tempArticles: [Article] = []
        for i in 0...30 {
            tempArticles.append(Article(title: "Article at index:\(i)"))
        }
        return tempArticles
    }()

    lazy var selectedRow: [Bool] = {
        return articles.map { _ in false }
    }()

    let cellId = "cell"



    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
    }




    // MARK: - Table view data source

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

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



    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
        cell.textLabel?.text = articles[indexPath.row].title

        // Set selected state to a cell
        cell.accessoryType = selectedRow[indexPath.row] ? .checkmark : .none
        return cell
    }


    // MARK: - Table view delegate

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // Update selection
        // This isn't the best way to update selection but just to make the example simple.
        selectedRow[indexPath.row] = !selectedRow[indexPath.row]
        tableView.reloadData()
    }
}

enter image description here

Ответы [ 3 ]

0 голосов
/ 08 июня 2018

Я бы использовал Set<Article> для отслеживания выбранных вами статей.Для этого ваша Article структура должна быть Hashable.Пока все свойства вашей структуры Hashable, все, что вам нужно сделать, это добавить соответствие протоколу Hashable.

struct Article: Hashable {
    let title: String
}


var selectedArticles = Set<Article>()

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
    let article = articles[indexPath.row]
    cell.textLabel?.text = article.title

    // Set selected state to a cell
    cell.accessoryType = selectedArticles.contains(article) ? .checkmark : .none
    return cell
}


// MARK: - Tabkle view delegate

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let article = article[indexPath.row]
    if selectedArticles.contains[article] {
        selectedArticles.remove(article)
    } else {
        selectedArticles.insert(article)
    }
    tableView.reloadRows(at: [indexPath], with: .none)
}
0 голосов
/ 11 июня 2018

I расширенный ответ Дориана Роя с использованием универсального типа .

Таким образом, нам нужно объявить его только один раз , а не длямодели всех типов

struct SelectableListItem<T> {
    let item: T
    var isSelected: Bool
}


Реализация табличного представления

    var listItems: [SelectableListItem<Article>] = []

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)

        let listItem = listItems[indexPath.row]
        cell.textLabel?.text = listItem.item.title
        cell.accessoryType = listItem.isSelected ? .checkmark : .none

        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // Update data
        listItems[indexPath.row].isSelected = !listItems[indexPath.row].isSelected

        // Update selection
        let cell = tableView.cellForRow(at: indexPath)
        cell?.accessoryType = listItems[indexPath.row].isSelected ? .checkmark : .none
    }
0 голосов
/ 08 июня 2018

Один из способов решить эту проблему: дать табличному представлению свою собственную модель, которая сохраняет состояние списка, включая выбранное состояние.

class ListItem {
    let article: Article
    var isSelected: Bool
}

Затем создайте табличное представление из массива этих элементов:

var listItems = [ListItem]()

Заполните этот массив списками ListItems, содержащими ваши статьи, и используйте его в качестве источника данных.

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

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
    let item = listItems[indexPath.row]
    cell.textLabel?.text = item.article.title 
    cell.accessoryType = item.isSelected ? .checkmark : .none
    return cell
}

И, наконец, в didSelectRowAtIndexPath вам просто нужно установить новое значение isSelectedвыбранного элемента списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...