自定义UITableViewCell内的UIButton导致在多个单元格

时间:2016-02-17 12:18:54

标签: ios swift uitableview uibutton

UITableView的目标是在其旁边显示带有自定义样式复选框的名称。但不知何故,当我点击复选框时,UITableView中的多个复选框被选中。

我用谷歌搜索并实施了不同问题的多种解决方案,但似乎都没有。

自定义UITableViewCell

import UIKit

class NameTableViewCell: UITableViewCell {

    var name = UILabel()

    let checkboxImage_unchecked = UIImage(named: "cellViewCheckbox_unchecked")
    let checkboxImage_checked = UIImage(named: "cellViewCheckbox_checked")

    let checkbox:UIButton

    weak var delegate:HandleCellInteractionDelegate?

    override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        self.checkbox = UIButton(frame: CGRectMake(35, 16, self.checkboxImage_unchecked!.size.width/2, self.checkboxImage_unchecked!.size.height/2))
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.backgroundColor = UIColor.transparant()

        self.checkbox.setBackgroundImage(self.checkboxImage_unchecked, forState: .Normal)
        self.checkbox.setBackgroundImage(self.checkboxImage_checked, forState: .Selected)

        self.name = UILabel(frame: CGRectMake(97,18,200, 30))

        self.addSubview(self.name)
        self.addSubview(self.checkbox)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    func checkboxPushed(sender:AnyObject){
        self.checkbox.selected = !self.checkbox.selected
        self.delegate?.didPressButton(self)            
    }

在协议中我声明了一个方法didPressButton作为按下按钮时的回调(委托需要实现它)

协定

import UIKit

protocol HandleCellInteractionDelegate:class {
    func didPressButton(cell:NameTableViewCell)
}

ViewController

import UIKit

class NameViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, HandleCellInteractionDelegate{

    var nameView:NameView {
        get {
            return self.view as! NameView
        }
    }

    var names:[Name]?
    var firstLetters:[String]?

    let cellIdentifier = "nameCell"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //self.view.backgroundColor = UIColor.darkSalmon()
    }

    override func loadView() {
        let bounds = UIScreen.mainScreen().bounds
        self.view = NameView(frame: bounds)
        if(NSUserDefaults.standardUserDefaults().objectForKey("gender") !== nil){
            self.loadJSON()
            self.getFirstLetters();
            self.nameView.tableView.delegate = self;
            self.nameView.tableView.dataSource = self;
            self.nameView.tableView.registerClass(NameTableViewCell.classForCoder(), forCellReuseIdentifier: "nameCell")
            self.nameView.tableView.separatorStyle = .None
            self.nameView.tableView.rowHeight = 66.5            }
    }

    func loadJSON(){
        let path = NSBundle.mainBundle().URLForResource("names", withExtension: "json")

        let jsonData = NSData(contentsOfURL: path!)


        self.names = NamesFactory.createFromJSONData(jsonData!, gender: NSUserDefaults.standardUserDefaults().integerForKey("gender"))
    }

    func getFirstLetters(){
        var previous:String = ""

        for name in self.names! {
            let firstLetter = String(name.name.characters.prefix(1))
            if firstLetter != previous {
                previous = firstLetter
                self.firstLetters?.append(firstLetter)
                print(firstLetter)
            }

        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return (self.names!.count)
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        return nameCellAtIndexPath(indexPath)
    }

    func nameCellAtIndexPath(indexPath:NSIndexPath) -> NameTableViewCell {
        let cell = self.nameView.tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! NameTableViewCell
        self.setNameForCell(cell, indexPath: indexPath)
        cell.delegate = self;
        cell.checkbox.addTarget(cell, action: "checkboxPushed:", forControlEvents: .TouchUpInside)
        return cell
    }

    func setNameForCell(cell:NameTableViewCell, indexPath:NSIndexPath) {
        let item = self.names![indexPath.row] as Name
        cell.name.text = item.name
    }

    func didPressButton(cell: NameTableViewCell) {
        print(cell)
    }

}

我做错了什么?我该如何解决?

2 个答案:

答案 0 :(得分:2)

您必须保存复选框状态。添加一个属性say checkboxStatus到你的模型(名称)。我希望你有indexpath.row。 在nameCellAtIndexPath

之后的这一行之后
cell.delegate = self;

像这样设置标签

cell.tag = indexPath.row;

在委托方法中,

func didPressButton(cell: NameTableViewCell) {
    print(cell)
    let item = self.names![cell.tag] as Name
    item.checkboxstatus = cell.checkbox.selected
}

只是一个重要的变化,

func nameCellAtIndexPath(indexPath:NSIndexPath) -> NameTableViewCell {
    let cell = self.tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as! NameTableViewCell
    self.setNameForCell(cell, indexPath: indexPath)
    cell.delegate = self;
    cell.tag = indexPath.row;
    cell.checkbox.addTarget(cell, action: "checkboxPushed:", forControlEvents: .TouchUpInside)
    let item = self.names![cell.tag] as Name
    cell.checkbox.selected = item.checkboxstatus
    return cell
}

干杯!

答案 1 :(得分:0)

这是因为正在重用UITableViewCell。

当您按下复选框时更改了单元格,您需要在数据源模型中跟踪它。

cellForRowAtIndexPath中,您必须添加条件以检查是否已选中该复选框。然后相应地显示相应的视图。

修改 在您的示例中,您需要检查nameCellAtIndexPath是否选中了复选框,然后将其显示正确。