Swift:多个 TableView 复选标记 - select 所有行

Swift: Multiple TableView checkmark - select all rows

可以在 TableView 中添加一个 select all 选项 Multiple checkmarks...?

我准备好了代码,我尝试做这个功能。请帮助我!

代码:

struct Area {
        let name : String
        var isSelected : Bool

        init(name : String, isSelected : Bool = false) {
            self.name = name
            self.isSelected = isSelected
        }
    }

    var areas = [Area(name: "Select all"),Area(name: "a"),Area(name: "b"),Area(name: "c"),Area(name: "d"]

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let area = areas[indexPath.row]
        cell.textLabel?.text = area.name
        cell.accessoryType = area.isSelected ? .checkmark : .none

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        areas[indexPath.row].isSelected.toggle()
        tableView.reloadRows(at: [indexPath], with: .none)
        let selectedAreas = areas.filter{[=12=].isSelected}.map{[=12=].name}
        print(selectedAreas)

    }

谢谢。

首先您需要为 table 视图启用多重选择

tableView.allowsMultipleSelection = true
tableView.allowsMultipleSelectionDuringEditing = true

Select 所有行

for section in 0..<tableView.numberOfSections {
        for row in 0..<tableView.numberOfRows(inSection: section) {
            let indexPath = IndexPath(row: row, section: section)
            tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
        }
    }

要在选中一行时启用复选标记:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) {
        let area = areas[indexPath.row]
        area.isSelected = true
        cell.accessoryType = .checkmark
    }
}

取消选择时也删除复选标记:

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) {
        let area = areas[indexPath.row]
        area.isSelected = false
        cell.accessoryType = .none
    }
}

如果有帮助,请为这个答案投票。谢谢

首先将您的区域更改为class,这样它将成为参考类型

    class Area {
        let name : String
        var isSelected : Bool

        init(name : String, isSelected : Bool = false) {
            self.name = name
            self.isSelected = isSelected
        }
    }

现在更改您的 didselect 逻辑

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

        let area = areas[indexPath.row]
        area.isSelected.toggle()
        if area.name == "Select all"{
          areas = areas.map{[=11=].isSelected = true}
        }
        tableView.reloadRows(at: [indexPath], with: .none)
        let selectedAreas = areas.filter{[=11=].isSelected}.map{[=11=].name}
        print(selectedAreas)

     }

您必须检查用户是否选择了第一行 ("Select all") 并相应地更新其他行:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // toggle the selected area
    areas[indexPath.row].isSelected.toggle()

    // save the new state for later use
    let isSelected = areas[indexPath.row].isSelected

    if indexPath.row == 0 {
        // "Select all" was selected – update all areas
        for i in 1..<areas.count {
            areas[i].isSelected = isSelected
        }

        // update UI
        tableView.visibleCells.forEach { [=10=].accessoryType = isSelected ? .checkmark : .none }
    } else {
        // update UI
        tableView.cellForRow(at: indexPath)?.accessoryType = isSelected ? .checkmark : .none
    }

    tableView.deselectRow(at: indexPath, animated: true)
}

推荐

要在视觉上分离关注点,您还可以为 "Select all" 行使用自己的 table 视图部分。在这种情况下,需要进行更多更改:

var areas = [
    // you do not need an area for "Select all" any longer
    Area(name: "a"),
    Area(name: "b"),
    Area(name: "c"),
    Area(name: "d")
]

var allSelected: Bool {
    // helper var to see if all areas are currently selected
    return areas.filter({![=11=].isSelected}).isEmpty
}

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

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    switch section {
    case 1: return "Areas"
    default: return nil
    }
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    switch section {
    case 0: return 1 // select all
    case 1: return areas.count
    default:
        // we should never get here
        fatalError()
    }
}

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

    if indexPath.section == 0 {
        cell.textLabel?.text = "Select all"
        cell.accessoryType = allSelected ? .checkmark : .none
    } else {
        let area = areas[indexPath.row]
        cell.textLabel?.text = area.name
        cell.accessoryType = area.isSelected ? .checkmark : .none
    }

    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.section == 0 {
        // (de-)select all
        let shouldSelect = !allSelected
        for i in 0..<areas.count {
            areas[i].isSelected = shouldSelect
        }
    } else {
        areas[indexPath.row].isSelected.toggle()
    }

    tableView.reloadRows(at: tableView.indexPathsForVisibleRows ?? [], with: .automatic)
}

didSelectRow中:

if indexPath.row == 0 { // the first item is the select all button
    // find out which areas should be selected
    let indicesThatShouldBeSelected = (1..<areas.count).filter { !areas[[=10=]].isSelected }
    // update model
    indicesThatShouldBeSelected.forEach { areas[[=10=]].isSelected = true }
    // update view
    tableView.reloadRows(at: indicesThatShouldBeSelected.map { IndexPath(section: 0, row: [=10=]) }, with: .none)
}

您也可以只执行 tableView.reloadData(),这会重新加载整个 table 视图,而不仅仅是需要重新加载的行。

如果 selectAll 行位于索引 0,请检查该行,然后将所有 isSelected 成员设置为 true 并重新加载整个 table

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if indexPath.row == 0 {
        areas.indices.forEach{areas[[=10=]].isSelected = true}
        tableView.reloadData()
    } else {
        areas[indexPath.row].isSelected.toggle()
        tableView.reloadRows(at: [indexPath], with: .none)
    }
    let selectedAreas = areas.filter{[=10=].isSelected}.map{[=10=].name}
    print(selectedAreas)

}

如果您想排除要选择的第一项,请删除第一个索引

areas.indices.dropFirst().forEach{areas[[=11=]].isSelected = true}