Галочка UITableViewCell для включения и выключения при нажатии

Я работаю над столом

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

Теперь у меня есть код, который делает эту работу:

// checkmarks when tapped

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let section = indexPath.section
    let numberOfRows = tableView.numberOfRowsInSection(section)
    for row in 0..<numberOfRows {
        if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: row, inSection: section)) {
            cell.accessoryType = row == indexPath.row ? .Checkmark : .None
        }
    }
}

но этот код выбирает только 1 ячейку внутри раздела (у меня есть 5 разделов)

Мне нужно, чтобы выбрать любую ячейку в любом месте

Также, когда я перетаскиваю свой экран вверх и вниз, я теряю галочкой

viewcontroller.swift

class ViewController: UIViewController, UITableViewDataSource {                        //class and subclass                  |)
//---------------------------------------------------------------------------------------------------------------------------/
    // Variable and constant, also IBAOutlet

    let section1 =
       ["this is used",
        "this is used to test",
        "this is used to test the lenght",
        "this is used to test the lenght of the text",
        "this is used to test the lenght of the text",
        "this is used to test the lenght of the text",
        "this is used to test the lenght of the text",
        "this is used to test the lenght of the text",
        "this is used to test the lenght of the text",]
    let section2 =
       ["this is used to test the lenght of the text"]
    let section3 =
       ["this is",
        "this is ",]


    @IBOutlet weak var scoreshow: UILabel!
    @IBOutlet weak var reset: UIButton!
    @IBOutlet weak var tableView: UITableView!

// --------------------------------------------------------------------------------------

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()
    }
//----------------------------------------------------------------------------------------
    // checkmarks when tapped

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
    {
        if let cell = tableView.cellForRowAtIndexPath(indexPath) {
            if cell.accessoryType == .Checkmark
            {
                cell.accessoryType = .None
            }
            else
            {
                cell.accessoryType = .Checkmark
            }
        }    
    }
//----------------------------------------------------------------------------------------
    //number of sections for the table

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 5
    }
//----------------------------------------------------------------------------------------
    //Calculate the amount of rows

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return self.section1.count;
    }
//----------------------------------------------------------------------------------------
    //Cells text label and config

    func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let cell:UITableViewCell = UITableViewCell(style:UITableViewCellStyle.Default, reuseIdentifier:"cell")
        cell.textLabel!.text = section1[indexPath.row]
        cell.textLabel!.numberOfLines = 0

        return cell
    }

//----------------------------------------------------------------------------------------

    @IBAction func resetswitch(sender: UIButton) {




    }
//----------------------------------------------------------------------------------------

}

15 ответов

Решение

Swift > 3.0

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

    }
}

Я решил с помощью двух функций Swift: didSelectRowAtIndexPath и didDeselectRowAtIndexPath.

override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
    if let cell = tableView.cellForRowAtIndexPath(indexPath) {
        cell.accessoryType = .None
    }
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if let cell = tableView.cellForRowAtIndexPath(indexPath) {
        cell.accessoryType = .Checkmark

    }
}

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

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("cellData", forIndexPath: indexPath) 
    if (some condition to initially checkmark a row)
        cell.accessoryType = .Checkmark
        tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: UITableViewScrollPosition.Bottom)
    } else {
        cell.accessoryType = .None
    }

    return cell
}

Попробуй это:

var checked = [Bool]() // Have an array equal to the number of cells in your table


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell

    //configure you cell here.
    if !checked[indexPath.row] {
        cell.accessoryType = .None
    } else if checked[indexPath.row] {
        cell.accessoryType = .Checkmark
    }
    return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    if let cell = tableView.cellForRowAtIndexPath(indexPath) {
        if cell.accessoryType == .Checkmark {
             cell.accessoryType = .None
             checked[indexPath.row] = false
        } else {
             cell.accessoryType = .Checkmark
             checked[indexPath.row] = true
        }
    }    
}

Чтобы сбросить все флажки:

func resetChecks() {
   for i in 0.. < tableView.numberOfSections {
       for j in 0.. < tableView.numberOfRowsInSection(i) {
            if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: j, inSection: i)) {
               cell.accessoryType = .None
            }
       }
   }
}

UITableView сохраняет выбранное состояние для одного или нескольких выборов. Поэтому у IMO должна быть очень веская причина для сохранения где-то целого параллельного состояния. Если вы хотите просто изменить внешний вид ячейки в зависимости от состояния выбора, сделайте это в ячейке.

В вашем подклассе UITableViewCell переопределите setSelected следующим образом:

override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
    self.accessoryType = selected ? .Checkmark : .None
}

Нет необходимости использовать какие-либо методы делегата табличного представления.

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

Swift 3.0
Использование только одной функции для простоты

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

    if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
        if cell.accessoryType == .checkmark {
            cell.accessoryType = .none
        } else {
            cell.accessoryType = .checkmark
        }
    }   
}

Swift 3.0

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) {
        cell.accessoryType = .checkmark
    }
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) {
        cell.accessoryType = .none
    }
}

Swift 4.0, теперь все вместе:

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var yourData = ["Cool","Sweet","Awesome"]

var checked = [Bool]()

override func viewDidLoad() {
    super.viewDidLoad()
    checked = Array(repeating: false, count: yourData.count)
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return searchData.count
}
func tableView(_ tableView: UITableView, cellForRowAt IndexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell

    //configure you cell here.
    if checked[IndexPath.row] == false{
        cell.accessoryType = .none
    } else if checked[IndexPath.row] {
        cell.accessoryType = .checkmark
    }

    return cell
}

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

    if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
        if cell.accessoryType == .checkmark {
            cell.accessoryType = .none
            checked[indexPath.row] = false
        } else {
            cell.accessoryType = .checkmark
            checked[indexPath.row] = true
        }
    }
}

}

Простым решением, как указывали другие, было бы .checkmark строка в didSelectRowAt метод и установите строку в .none в didDeselectRowAtметод следующим образом...

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

    tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

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

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    for row in 0..<tableView.numberOfRows(inSection: indexPath.section) {
        if let cell = tableView.cellForRow(at: IndexPath(row: row, section: indexPath.section)) {
            cell.accessoryType = row == indexPath.row ? .checkmark : .none
        }
    }
}

Swift 5.0

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

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

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    self.tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

func resetChecks() {
    for i in 0..<tableView.numberOfSections {
        for j in 0..<tableView.numberOfRows(inSection: i) {
            if let cell = tableView.cellForRow(at: IndexPath(row: j, section: i)) {
                cell.accessoryType = .none
            }
        }
    }
}

Обновлено в Swift 4.2 Каждый новый выбор Удалить предыдущую галочку

   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print(self.coloursArray[indexPath.row])

     self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}

func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    self.tableView.cellForRow(at: indexPath)?.accessoryType = .none
}

Самое простое решение, которое помогло мне (Swift 5.2)

override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
    // Remove checkmark from the row that is currently showing it before adding to one being selected
    if let currentIndexPath = tableView.indexPathForSelectedRow {
        self.tableView.cellForRow(at: currentIndexPath)?.accessoryType = .none
    }

    return indexPath
}

override public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}

Для Swift 5:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
        cell.accessoryType = .checkmark
    }

}

override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
        cell.accessoryType = .none
    }
}

Для всех, кто использует одноразовую галочку.

      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
       
        tableView.deselectRow(at: indexPath, animated: true)
        
        //  checkmark logic
        if let cell = tableView.cellForRow(at: indexPath as IndexPath) {
                if cell.accessoryType != .checkmark {
                    resetChecks()
                    cell.accessoryType = .checkmark
                }
            }
    }
func resetChecks() {
        for i in 0..<tableView.numberOfSections {
            for j in 0..<tableView.numberOfRows(inSection: i) {
                if let cell = tableView.cellForRow(at: NSIndexPath(row: j, section: i) as IndexPath) {
                    cell.accessoryType = .none
                }
           }
       }
    }

Поскольку я не видел, чтобы кто-то перечислял это, вы можете создать собственный UITableViewCell который переключит галочку с выделением, переопределив его setSelected() метод и дефолт .selectionStyle к .gray:

class CheckableTableViewCell: UITableViewCell {

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        selectionStyle = .gray
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        accessoryType = selected ? .checkmark : .none
    }
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    if self.checkedIndex == indexPath.row{

    }else{
        let cell = tableView.cellForRow(at: indexPath)
        cell?.accessoryType = .checkmark
        let indexPathh = IndexPath(row: checkedIndex, section: 0)
        let UnCheckCell = tableView.cellForRow(at: indexPathh)
        UnCheckCell?.accessoryType = .none
        checkedIndex = indexPath.row
    }
}

Я использовал tableView(_:didSelectRowAt:), метод делегата для выполнения этой функции установки флажка на ячейке и удаления ее при повторном нажатии на ячейку. Вот код:

//MARK:-create delegate methode that is fired when a cell is clicked
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
     tableView.deselectRow(at: indexPath , animated: true)


     if  let cell = tableView.cellForRow(at: indexPath){
         if cell.accessoryType == .checkmark {
             cell.accessoryType = .none
         }
         else {
             cell.accessoryType = .checkmark
         }
     }
     
     
 }
Другие вопросы по тегам