自定义 UITableViewCell 中的 UIButton 导致在多个单元格中选择按钮

Posted

技术标签:

【中文标题】自定义 UITableViewCell 中的 UIButton 导致在多个单元格中选择按钮【英文标题】:UIButton inside custom UITableViewCell causes button to be selected in multiple cells 【发布时间】:2016-02-17 12:18:54 【问题描述】:

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)

视图控制器

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)
    


我做错了什么以及如何解决?

【问题讨论】:

在单元格中添加目标,而不是在视图控制器中。多重选择是立即的,还是仅在您滚动时? @Wain 我不知道它是否是即时的,因为它从不可见的单元格中选择按钮,但是当我滚动时,按钮的选中状态消失 【参考方案1】:

您必须保存复选框状态。向您的模型(名称)添加一个属性,例如 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

干杯!

【讨论】:

【参考方案2】:

这是因为 UITableViewCell 正在被重用。

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

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

编辑: 在您的示例中,您需要检查 nameCellAtIndexPath 是否选中复选框,然后正确显示。

【讨论】:

感谢您的快速回复!我会尽快试试这个:)

以上是关于自定义 UITableViewCell 中的 UIButton 导致在多个单元格中选择按钮的主要内容,如果未能解决你的问题,请参考以下文章

在 Storyboard 中设计的自定义 UITableViewCell 中的自定义 UIView

ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局

iOS开发UI篇—使用xib自定义UItableviewcell实现一个简单的团购应用界面布局

将自定义 UITableViewCell 从 nib 加载到 Swift 中的 UIViewController

ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局

iOS开发UI篇—使用xib自定义UItableviewcell实现一个简单的团购应用界面布局