UITableView的“自定义单元格”按钮会从主视图中选择其他按钮吗?

时间:2018-09-04 08:16:36

标签: ios swift uitableview uibutton tableview

在我的自定义tableviewcell上,我有一个按钮,用户可以按该按钮在选定和未选定之间切换。这只是一个简单的UIButton,此按钮包含在我的customtableviewcell中,作为插座。

import UIKit

class CustomCellAssessment: UITableViewCell {

@IBOutlet weak var name: UILabel!
@IBOutlet weak var dateTaken: UILabel!
@IBOutlet weak var id: UILabel!
@IBOutlet weak var score: UILabel!
@IBOutlet weak var button: 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
}

@IBAction func selectButton(_ sender: UIButton) {

if sender.isSelected{

  sender.isSelected = false

}else{
  sender.isSelected = true
} 
} 
}

奇怪的是,当我在第一个单元格上按一个按钮时,它随后在同一表视图中的另一个单元格(视图外)上向下选择了8个单元格的按钮。每个单元格都有自己的按钮,但是好像使用dequeReusableCell导致系统以这种方式运行一样。为什么这样做,并且与UIbutton在tableviewcell上的工作方式有关?

谢谢

4 个答案:

答案 0 :(得分:1)

点击按钮时,将设置按钮的选定状态。当单元被重用时,按钮仍处于选中状态-您无需执行任何操作即可重置或更新该状态。

如果按钮选择与表格单元格选择分开,那么您需要跟踪所选按钮的索引路径作为数据模型的一部分,然后在{{ 1}}。

表视图将仅创建所需的单元格,以显示一屏左右的信息。之后,单元将被重用。如果某个单元格滚动到屏幕顶部之外,则表格视图会将其置于重用队列中,然后在滚动时需要在底部显示新行时,它将其从队列中拉出并提供给您tableView(_: cellForRowAt:)

您在此处获得的单元将与您之前使用8行左右的单元完全相同,完全由您决定。您可以在tableView(_: cellForRowAt:)中做到这一点,并且通过实现cellForRow也可以在单元格本身中获得机会,这在单元格出队之前就被调用。

答案 1 :(得分:1)

  

每个单元格都有其自己的按钮,但这就像使用dequeReusableCell导致系统以这种方式运行一样。

错了。 UITableViewCells是可重用的,因此,如果您的tableView有8个可见的单元格,则在加载第9个单元格时,单元格nr 1将被重用。

解决方案:您需要跟踪细胞状态。调用方法cellForRowAtIndexPath时,您需要从头开始配置单元格

您可能在ViewController中有一个包含单元格状态的小数组:

var cellsState: [CellState]

并在其中存储每个indexPath的选定状态。然后在cellForRowAtIndexPath中,用状态配置单元格。

cell.selected = self.cellsState[indexPath.row].selected

因此,我要做的概述是:

1-在cellForRowAtIndexPath上,我将设置

cell.button.tag = indexPath.row
cell.selected = cellsState[indexPath.row].selected

2-将IBAction移至ViewController或TableViewController

3-调用click方法时,更新单元格的选定状态

self.cellsState[sender.tag].selected = true

请记住,始终将整个单元配置为cellForRowAtIndexPath

编辑:

import UIKit

struct CellState {
    var selected:Bool
    init(){
        selected = false
    }
}

class MyCell: UITableViewCell {

    @IBOutlet weak var button: UIButton!

    override func awakeFromNib() {
        self.button.setTitleColor(.red, for: .selected)
        self.button.setTitleColor(.black, for: .normal)
    }

}

class ViewController: UIViewController, UITableViewDataSource {

    var cellsState:[CellState] = []

    @IBOutlet weak var tableView: UITableView!


    override func viewDidLoad() {
        super.viewDidLoad()

        //Add state for 5 cells.
        for _ in 0...5 {
            self.cellsState.append(CellState())
        }
    }   


    @IBAction func didClick(_ sender: UIButton) {

        self.cellsState[sender.tag].selected = true
        self.tableView.reloadData()
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! MyCell
        cell.button.isSelected = self.cellsState[indexPath.row].selected
        cell.button.tag = indexPath.row
        return cell
    }
}

答案 2 :(得分:0)

在您的~> cs sbt/sbt --branch 1.2.1 Repository not found on github 中,采取措施单击按钮并添加目标

tableView(_: cellForRowAt:)

在目标方法中,使用以下几行来获取cell.button.addTarget(self, action: #selector(self.selectedButton), for: .touchUpInside)

indexPath

然后使用该func selectedButton(sender: UIButton){ let hitPoint: CGPoint = sender.convert(CGPoint.zero, to: self.tableView) let indexPath: NSIndexPath = self.tableView.indexPathForRow(at: hitPoint)! as NSIndexPath } 完成您的工作。 实际上,您的方法找不到单击indexPath按钮的位置,这就是为什么您无法使用所需按钮的原因。

答案 3 :(得分:0)

解决问题的一种方法如下

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { string dbPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); if (!optionsBuilder.IsConfigured) { optionsBuilder.UseSqlite($@"Data Source={dbPath}\sqlite\.sample.sqlite"); Batteries.Init(); base.OnConfiguring(optionsBuilder); } }

1. First create a protocol to know when button is clicked

protocol MyCellDelegate: class { func cellButtonClicked(_ indexPath: IndexPath) }

2. Now in your cell class, you could do something like following

class MyCell: UITableViewCell { var indexPath: IndexPath? weak var cellButtonDelegate: MyCellDelegate? func configureCell(with value: String, atIndexPath indexPath: IndexPath, selected: [IndexPath]) { self.indexPath = indexPath //set the indexPath self.textLabel?.text = value if selected.contains(indexPath) { //this one is selected so do the stuff //here we will chnage only the background color backgroundColor = .red self.textLabel?.textColor = .white } else { //unselected backgroundColor = .white self.textLabel?.textColor = .red } } @IBAction func buttonClicked(_ sender: UIButton) { guard let delegate = cellButtonDelegate, let indexPath = indexPath else { return } delegate.cellButtonClicked(indexPath) } }

3. Now in your controller. I'm using UItableViewController here