自定义 UITableViewCell 中的按钮操作会影响其他单元格

Posted

技术标签:

【中文标题】自定义 UITableViewCell 中的按钮操作会影响其他单元格【英文标题】:Button action in custom UITableViewCell affects other cells 【发布时间】:2015-09-14 05:46:01 【问题描述】:

我有一个 TablewView,它的原型 UITableViewCell 有自己的类,

自定义 UITableViewCell 类

import UIKit

class H_MissingPersonTableViewCell: UITableViewCell 

    @IBOutlet weak var strName: UILabel!
    @IBOutlet weak var imgPerson: UIImageView!
    @IBOutlet weak var Date1: UILabel!
    @IBOutlet weak var Date2: UILabel!
    @IBOutlet weak var MainView: UIView!
    @IBOutlet weak var btnGetUpdates: UIButton!
    @IBOutlet weak var btnComment: UIButton!
    @IBOutlet weak var btnReadMore: UIButton!
    
    
    override func awakeFromNib() 
        super.awakeFromNib()
        // Initialization code
    

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

        // Configure the view for the selected state
    


TableView 加载完美,数据源和委托工作正常。但是,当我单击 IndexPath.row = 0(零)处的 BUTTON,然后向下滚动时,我会看到 random(?) 或其他单元格也因单击第 0 行中的 BUTTON 而被突出显示...

这是我的 CellForRowAtIndexPath 代码:

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
        
        println("called")
        var cell : CustomCell
        
        
        cell = tableView.dequeueReusableCellWithIdentifier("CustomCellID", forIndexPath: indexPath) as! CustomCell
        cell.strName.text = self.names[indexPath.row]
        cell.imgPerson.image = UIImage(named: "\(self.persons[indexPath.row])")!

        cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnGetUpdates.layer.borderWidth = 1
        cell.btnGetUpdates.layer.cornerRadius = 5.0
        

        cell.btnComment.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnComment.layer.borderWidth = 1
        cell.btnComment.layer.cornerRadius = 5.0
        
        cell.btnReadMore.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnReadMore.layer.borderWidth = 1
        cell.btnReadMore.layer.cornerRadius = 5.0
        
        cell.dateMissingPersonPlace.text = self.MissingPeoplePlace[indexPath.row]
        cell.dateMissingPersonSince.text = self.MissingPeopleSince[indexPath.row]
        
        cell.btnGetUpdates.tag = indexPath.row
        cell.btnGetUpdates.addTarget(self, action: "GetUpdatesButton:", forControlEvents: .TouchUpInside)
        
        return cell
        
    

在我的 cell.btnGetUpdates 中,我执行了一个操作,正如您在 CellForIndex 代码的最后一部分中看到的那样,GetUpdatesButton:

这是代码:

func GetUpdatesButton(sender: UIButton)
    println("Button Clicked \(sender.tag)")

    var sen: UIButton = sender
    var g : NSIndexPath = NSIndexPath(forRow: sen.tag, inSection: 0)
    var t : CustomCell = self.myTableView.cellForRowAtIndexPath(g) as! CustomCell
    t.btnGetUpdates.backgroundColor = UIColor.redColor()
    

问题是,不仅索引 0 中的按钮被突出显示,而且当我向下滚动 tableView 时,我还会看到来自其他索引/行的随机按钮被突出显示。

我哪里出错了,我怎么只能更新我点击的按钮……而不是其他按钮……

我有 20 个项目(20 行),当我单击第 0 行中的按钮时,第 3、6、9 行......也有突出显示的按钮。

第 0 行,点击按钮

ROW 3,按钮也被点击了,虽然我并没有真正点击它。

【问题讨论】:

这是一个非常常见的问题——你会在 SO 上找到很多关于它的问题。滚动时会重复使用单元格,因此您不能将状态数据存储在单元格对象中。您必须将状态存储在其他数据模型中,并使用它在cellForRowAtIndexPath 中设置按钮状态 - 即,如果它应该关闭则将其关闭,如果它应该打开则将其打开。 您可以在此处查看我的答案 - ***.com/questions/27918584/… - 该答案设置了一个复选标记,但您可以使用与按钮处理程序相同的方法并设置按钮颜色。主要思想是使用 NSMutableIndexSet 来存储所选项目 您好,非常感谢!我会看看这个,让你知道一段时间:) 我无法将 button.tag 添加到 NSMutableIndexSet 数组中... 您好我的问题没有解决,感谢您的回答,它帮助我掌握了概念,我使用了一个 INT 数组并将 indexPath.row 保存在那里,然后在 CellForRowAtIndex 中进行比较 【参考方案1】:

这是由于 UITableview 具有可重用单元策略而发生的。为了解决此问题,您需要在 cellForRowAtIndexPath 方法中维护一个选定项目数组,您必须验证该按钮是否被选定项目数组持有。如果是,则应用选择样式,否则应用普通样式。

查看下面的按钮点击源代码:

func GetUpdatesButton(sender: UIButton) 

    var sen: UIButton = sender
    var g : NSIndexPath = NSIndexPath(forRow: sen.tag, inSection: 0)
    var t : CustomCell = self.myTableView.cellForRowAtIndexPath(g) as!   CustomCell
    t.btnGetUpdates.backgroundColor = UIColor.redColor()
   self.selectedButtonsArray.addObject(indexpath.row)

以下代码用于在 CellForRowAtIndexPath 中的按钮上应用样式:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    var cell : CustomCell
    cell = tableView.dequeueReusableCellWithIdentifier("CustomCellID", forIndexPath: indexPath) as! CustomCell
    cell.strName.text = self.names[indexPath.row]
    cell.imgPerson.image = UIImage(named: "\(self.persons[indexPath.row])")!

    if(self.selectedButtonsArray.containsObject(indexpath.row))

        cell.btnGetUpdates.backgroundColor = UIColor.redColor()
        cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnGetUpdates.layer.borderWidth = 1
        cell.btnGetUpdates.layer.cornerRadius = 5.0

    else

        cell.btnGetUpdates.layer.borderColor = UIColor.darkGrayColor().CGColor
        cell.btnGetUpdates.layer.borderWidth = 1
        cell.btnGetUpdates.layer.cornerRadius = 5.0

   

    cell.btnComment.layer.borderColor = UIColor.darkGrayColor().CGColor
    cell.btnComment.layer.borderWidth = 1
    cell.btnComment.layer.cornerRadius = 5.0

    cell.btnReadMore.layer.borderColor = UIColor.darkGrayColor().CGColor
    cell.btnReadMore.layer.borderWidth = 1
    cell.btnReadMore.layer.cornerRadius = 5.0

    cell.dateMissingPersonPlace.text = self.MissingPeoplePlace[indexPath.row]
    cell.dateMissingPersonSince.text = self.MissingPeopleSince[indexPath.row]

    cell.btnGetUpdates.tag = indexPath.row
    cell.btnGetUpdates.addTarget(self, action: "GetUpdatesButton:",forControlEvents: .TouchUpInside)

    return cell

我希望这有助于解决您的问题!谢谢。

【讨论】:

嗨,非常感谢您的回答,我刚刚做了这个并且它的工作,但是......按钮,当点击时,没有立即更改或更新,我需要向下滚动然后向上滚动以查看更改...有什么建议吗? 我也注意到单击 CELL 0 中的按钮,当我滚动时也会更改其他单元格中的其他按钮......即使在将 if 条件放入 CellForRow 之后 您好我的问题没有解决,感谢您的回答,它帮助我掌握了概念,我使用了一个 INT 数组并将 indexPath.row 保存在那里,然后在 CellForRowAtIndex 中进行比较【参考方案2】:

在 GetUpdatesButton() 函数中,将 indexPath.row 值的标志值保存在单独的数组中。然后重新加载表格视图的特定单元格。

现在在 cellForRowAtIndexPath 函数中设置检查标志值是否设置的条件,如果设置则更改背景颜色,否则设置默认颜色。

PS。有不同的解决方法来解决这个问题。只需了解逻辑并选择对代码有用的逻辑即可。

【讨论】:

谢谢,我理解并尝试通过存储单击按钮的 NSINdexpath 来做到这一点(如果按钮在第 0 行,那么我存储 NSIndexPath(0,0) )但它不起作用...我仍然看到与这篇文章相同的结果....你能详细说明一下吗? 当我点击 CELL 0 时,当我向下滚动时,我还会看到来自其他单元格的随机按钮也被突出显示 您好我的问题没有解决,感谢您的回答,它帮助我掌握了概念,我使用了一个 INT 数组并将 indexPath.row 保存在那里,然后在 CellForRowAtIndex 中进行比较【参考方案3】:

这是因为细胞正在被重复使用。 因此,当您使用按钮操作为单元格着色时,正在绘制单元格的背景,我猜这工作正常,但情况是当您向上或向下滚动时,前一个具有 bg 颜色的单元格被重用,因此您得到之前的设置。

提示是在此方法func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 中显式设置UIButtonUITableViewCell 的背景颜色,因为每次重复使用时,颜色将设置为默认颜色,您将不会获得以前的颜色它正在被重用。

设置好了

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
  cell.backgroundColor = [UIColor whiteColor];
  cell.btnGetUpdates setBackgroundColor:[UIColor whiteColor];
//with along the other code, add these two lines.

编辑

为了获得您想要的效果,请设置一个实例变量,该变量存储所选单元格的 indexPath,类似于 int。

在按钮操作方法中将 int 存储到 button.tag 属性中,该属性也是单元格的 indexpath.row 属性。

在你的cellForRowAtIndexPath 方法中,做一个检查

if(indexpath.row == selectedIntIndexPath)
  //change the colour whatever you want.

最后在按钮的IBAction方法中调用[self.tableView reloadData]

所以完整的代码会是这样的

@implementation ViewController
int selectedIntIndexPath;


 -(IBAction)actionForButton:(id)sender
UIButton *btn = (UIButton *)sender;
selectedIntIndexPath = btn.tag;
[self.customTableView reloadData];


-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
UICustomTableViewCell *cell = (UICustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"reuseIdentifire" forIndexPath:indexPath];
if(indexPath.row == selectedIntIndexPath)
    // do your colour
  
 return cell;

【讨论】:

非常感谢! :) 我会试试这个,过一段时间再告诉你 我尝试通过在 var clickedButton: [NSIndexPath] = [] 中获取其 TAG(标签设置为 indexath.row)来存储单击按钮的 NSIndexPath,我在 CellForRowAtIndex 中使用了它 if(self.clickedButton.contains(indexPath)) cell.btnGetUpdates.layer.borderColor = UIColor.redColor().CGColor cell.btnGetUpdates.layer.borderWidth = 1 cell.btnGetUpdates.layer。 cornerRadius = 5.0 else cell.btnGetUpdates.layer.borderColor = UIColor.redColor().CGColor cell.btnGetUpdates.layer.borderWidth = 1 cell.btnGetUpdates.layer.cornerRadius = 5.0 我最终看到每个按钮都有 RED BORDER COLOR(据说,它应该只在单击按钮时发生,所以我猜它仍然无法正常工作_ 您必须在cellForRowAtIndexPath 方法中将背景颜色设置为白色【参考方案4】:

这是我的解决方案,以扩展@RaymondLedCarasco 评论:

在 Swift 4 Xcode 9.3 中测试

声明财产:

var numberCells: [Int] = []

点击单元格按钮时:

self.numberCells.append(indexPath.row)

在 CellForRowAtIndex 中检查:

if self.numberCells.contains(indexPath.row)  ...  else  ... 

【讨论】:

【参考方案5】:

这里我已经解决了大部分 TableViewCell 问题,比如在滚动剩余行后单击 单元格按钮 时,以及在 didSelectRowAt indexPath: IndexPath 处选择该行时, 滚动后可以选择剩余的行。所以我创建了一个应用程序来解决这些问题。这里添加GitHub代码Find the code

在第一个屏幕中,单击红色按钮并向下滚动您不会看到 UITableViewCell 中的其他单元格自动受到影响。

在第一个屏幕中单击 didSelectRowAt indexPath: IndexPath,您可以转到第二个屏幕的详细信息屏幕,在该屏幕中选择一行后不会自动选择其他行UITableViewCell。

【讨论】:

以上是关于自定义 UITableViewCell 中的按钮操作会影响其他单元格的主要内容,如果未能解决你的问题,请参考以下文章

用作自定义 UITableViewCell 的 XIB 中的自定义按钮不响应点击(ios7)

自定义 UITableViewCell 中的操作按钮调用的 UITableView reloadRows() 总是落后一步

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

如何从 UITableViewCell 中的自定义 UIButton 中删除触摸延迟

如何得到自定义UITableViewCell中的按钮所在的cell的indexPath.row

自定义 uitableviewcell 中的 Uibuttons