UITableView自定义单元格按钮从主视图中选择其他按钮?

问题描述 投票:0回答:4

在我的自定义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
} 
} 
}

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

谢谢

ios swift uitableview uibutton tableview
4个回答
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
    }
}

1
投票

点击按钮时,您将设置按钮的选定状态。当单元格被重用时,按钮仍处于选中状态 - 您没有做任何事情来重置或更新该状态。

如果按钮选择与表格单元格选择分开,则需要跟踪所选按钮的索引路径作为数据模型的一部分,然后更新tableView(_: cellForRowAt:)中按钮的选定状态。

表视图将只创建所需数量的单元格,以显示一个屏幕和一位信息。之后,细胞被重复使用。如果一个单元格从屏幕顶部滚动,表格视图将其置于重用队列中,然后当您需要在滚动时在底部显示一个新行时,它会将其拉出队列并将其提供给您tableView(_: cellForRowAt:)

您在此处获得的单元格与之前使用8行左右的单元格完全相同,您可以完全配置它。您可以在cellForRow中执行此操作,并且您还可以通过实现prepareForReuse在单元格本身中获得机会,tableView(_: cellForRowAt:)在单元格出列之前调用。


0
投票

在你的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

然后使用那个indexPath做你的东西。实际上你的方法找不到点击哪个1. First create a protocol to know when button is clicked按钮,这就是为什么不使用你想要的按钮。


0
投票

解决问题的一种方法如下

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

class TheTableViewController: UITableViewController, MyCellDelegate { let cellData = ["cell1","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4","cell2","cell3","cell4"] var selectedIndexpaths = [IndexPath]() override func viewDidLoad() { super.viewDidLoad() tableView.register(MyCell.self, forCellReuseIdentifier: "MyCell") } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return cellData.count } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 55.0 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell cell.cellButtonDelegate = self cell.configureCell(with: cellData[indexPath.row], atIndexPath: indexPath, selected: selectedIndexpaths) return cell } override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 30.0 } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) as! MyCell cell.buttonClicked(UIButton()) } func cellButtonClicked(_ indexPath: IndexPath) { if selectedIndexpaths.contains(indexPath) { //this means cell has already selected state //now we will toggle the state here from selected to unselected by removing indexPath if let index = selectedIndexpaths.index(of: indexPath) { selectedIndexpaths.remove(at: index) } } else { //this is new selection so add it selectedIndexpaths.append(indexPath) } tableView.reloadData() } }

qazxswpoi
© www.soinside.com 2019 - 2024. All rights reserved.