【问题标题】:How to prevent cells from mirroring button pressed action in another cell?如何防止单元格在另一个单元格中镜像按钮按下操作?
【发布时间】:2020-02-24 19:22:24
【问题描述】:

I have 3 buttons in the cells of my tableview, they buttons are in a @IBAction button collection so when one is selected it turns the button color from blue to red and deselects the button previously pressed to back to blue.执行这些操作时代码运行良好

我遇到的问题是,当在一个单元格中选择一个按钮时,会在另一个单元格中选择完全相同的按钮,如下所示▼

到目前为止,我尝试的方法不起作用,我认为可能起作用的是我在视图控制器中创建一个“@objc func”,但我不知道从我创建的内容中去哪里以防止“镜像”在细胞中

我知道我接近解决方案 提前感谢您提供的任何帮助

How to update UILabel on a button click in UITableViewCell in swift 4 and xcode 9?

import UIKit

class Cell: UITableViewCell {

    @IBOutlet weak var lbl1: UILabel!
    @IBOutlet weak var lbl2: UILabel!
    @IBOutlet weak var lbl3: UILabel!

    @IBOutlet weak var btn1: RoundButton!
    @IBOutlet weak var btn2: RoundButton!
    @IBOutlet weak var btn3: RoundButton!

    var lastSelectedButton = UIButton()
    @IBAction func cartTypeSelected(_ sender: RoundButton) {
        lastSelectedButton.isSelected = false; do {
            self.lastSelectedButton.backgroundColor = UIcolor.blue
        } //Plus any deselect logic for this button
        lastSelectedButton = sender //If any buttons are not affect by this selection logic exclude them here
        sender.isSelected = true; do {
            self.lastSelectedButton.backgroundColor = UIColor.red
        }
    }
}

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
         super.viewDidLoad()

         tableView.dataSource = self
         tableView.delegate = self

    }
    var lastSelectedButton = UIButton()
    @objc func selectedButton(_ sender: RoundButton) {
        lastSelectedButton.isSelected = false; do {
            self.lastSelectedButton.backgroundColor = UIcolor.blue
        } //Plus any deselect logic for this button
        lastSelectedButton = sender 
        sender.isSelected = true; do {
            self.lastSelectedButton.backgroundColor = UIColor.red
        }
    }
}

extension View[![enter image description here][1]][1]Controller: UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? Cell else { return UITableViewCell() }

        return cell
    }
}

【问题讨论】:

    标签: ios swift button colors cell


    【解决方案1】:

    你好,伊芙琳!使用委托模式! :)

    这里有一些解释可以帮助你继续前进:

    1. 创建一个模型来表示您的表格视图内容

    我们可以使用什么样的模型来表示只选择一个按钮的状态?枚举可以表示(将其添加到单独的文件或控制器中):

    enum ButtonSelectionIdentity {
        case first
        case second
        case third
    }
    

    我们的表格视图将呈现一个由这些枚举组成的数组,在控制器中,让我们添加一个实例变量来保存数据,并用一个空数组对其进行初始化:

    private var elements: [ButtonSelectionIdentity] = []
    

    让我们用 100 个元素填充这个数组,默认为第一个被选中的按钮,在你的控制器 viewDidLoad 函数中,添加:

        for i in 0..<100 {
            elements.append(ButtonSelectionIdentity.first)
        }
    
    1. 确保从模型更新单元格

    所以现在我们有一个模型(ButtonSelectionIdentity 的数组),我们希望表视图控制器反映该模型。为此,我们改变了控制器如何符合UITableViewDataSource 的原始方式。我们需要新的实现来从数组中获取数据:

    extension ViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return elements.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? Cell else { 
                return UITableViewCell() 
            }
    
            let model = elements[indexPath.row]
            cell.update(with: model)
    
            return cell
        }
    }
    

    是的,经过上述修改后它不会编译,直到我们为单元类添加更新方法:

    func update(with model: ButtonSelectionIdentity) {
        btn1.backgroundColor = .blue
        btn2.backgroundColor = .blue
        btn3.backgroundColor = .blue
    
        switch model {
        case .first:
            btn1.backgroundColor = .red
        case .second:
            btn2.backgroundColor = .red
        case .third:
            btn3.backgroundColor = .red
        }
    }
    

    编译并运行,您应该会看到 100 个单元格的第一个正方形为红色。

    1. 让单元格动作连接到控制器

    删除控制器类中的buttonSelected 方法,并删除Cell 类中的btnTypeSelected 方法,以便我们重新开始。

    在这个阶段,我们有一个元素数组,它们显示在控制器内部的表格视图中。控制器拥有它,因为它创建了它。单元格仅用于呈现控制器所具有的状态。因此,为了让我们的单元格更新,我们需要告诉控制器我们正在更新。为此,我们可以使用委托模式。让我们创建一个单元委托协议来描述它。

    在您的Cell 类文件中,在class Cell ... 之前,添加:

    protocol CellDelegate: class {
        func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity)
    }
    

    所以这是我们将用来让控制器了解单元格中状态变化的委托。让我们向委托添加对单元格的弱引用。在您的Cell 中,添加:

    weak var delegate: CellDelegate?
    

    现在,让您的控制器符合CellDelegate 协议。在您的控制器类中,添加:

    extension ViewController: CellDelegate {
        func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
        }
    }
    

    现在我们将其留空,稍后再完成。

    现在,控制器可以成为单元格的代表。让它成为一个! 更新控制器的cellForRowAt 方法,如下:

        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? Cell else { 
                return UITableViewCell() 
            }
    
            let model = elements[indexPath.row]
            cell.update(with: model)
            cell.delegate = self
    
            return cell
        }
    

    完成,我们将控制器配置为单元格的代理!让我们利用它!

    1. 制作控制器更新模型,当单元报告它的状态变化时

    在您的单元格中,分别连接每个按钮上的 IBActions:

    @IBAction func onFirstButtonTapped(_ sender: RoundButton) {
    }
    
    @IBAction func onSecondButtonTapped(_ sender: RoundButton) {
    }
    
    @IBAction func onThirdButtonTapped(_ sender: RoundButton) {
    }
    

    每当一个按钮被点击时,我们希望我们的单元告诉控制器状态改变,例如:

    @IBAction func onFirstButtonTapped(_ sender: RoundButton) {
        delegate?.onCellModelChange(cell: self, model: .first)
    }
    

    相应地实现其他两种方法。

    在您的控制器中,让我们重新访问onCellModelChange 方法。现在单元格上发生了一个动作,我们需要在elements 数组中找到一个元素,对应于那个单元格。为此,我们可以使用tableView-s -indexPath(for:) 方法:

    extension ViewController: CellDelegate {
        func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
            guard let indexPath = tableView.indexPath(for: cell) else {
                return
            }
            print(indexPath)
        }
    }
    

    如果您运行应用程序,在此阶段您应该会看到与您按下按钮的单元格对应的索引路径的日志。 还不是我们需要的。

    我们的表格视图只呈现单个部分,因此我们可以从索引路径中忽略该部分,而只考虑一行,这将与我们的元素索引相同。让我们使用这个索引更新数组中的值:

    extension ViewController: CellDelegate {
        func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
            guard let indexPath = tableView.indexPath(for: cell) else {
                return
            }
            let index = indexPath.row
            elemets[index] = model
        }
    }
    

    现在,如果您运行此程序,您应该会更新模型,但单元格的状态不会立即更新。如果您将单元格滚动到屏幕外,然后再次向后滚动,您仍然可以看到它正在工作。

    最后一点是立即更新单元格。我们怎么能做到这一点?让我们将更新后的模型放回单元格:

    extension ViewController: CellDelegate {
        func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
            guard let indexPath = tableView.indexPath(for: cell) else {
                return
            }
            let index = indexPath.row
            elemets[index] = model
            cell.update(with: model)
        }
    }
    

    应该就是这个了! 我没有测试它也没有编译它:)所以如果你发现任何错别字,请告诉我:) 干杯

    【讨论】:

    • 有效!但是如果说它有一个类来控制表格视图中单元格的数量,我将如何转换它,比如说如果这个类被称为标签并且它替换了选择 1、2 和 3 的文本,很抱歉让我感到很痛苦,因为我仍在完成我的项目,但我只是忘记在问题中提出这个问题,但非常感谢所有帮助
    • 因为它适用于我所做的更改,直到我在 cell.update (with: model) & cell.delegate = self
    • 如果您希望您的单元格代表第一个/第二个/第三个按钮选择和一些标签,您应该更新您的模型。枚举不再涵盖您需要的内容,因此,创建一个包含枚举和标签的结构。 struct CellModel { let buttonSelectionIdentity: ButtonSelectionIdentity let labels: Labels }
    • 在你的控制器中使用这个结构代替elementsprivate var elements: [CellModel] = []
    • 并相应地更新:viewDidLoad 应该填充新结构,单元格的更新方法应该采用CellModel 就是这样。
    【解决方案2】:

    您在 tableview 中使用 dequeuereusablecell。顾名思义,这些单元是可重复使用的。这意味着,当您滚动表格视图时,单元格的某些 UI 方面的行为可能类似。

    为了防止这种情况,您总是需要一个“else”语句。

    sender.isSelected = true; do {
        self.lastSelectedButton.backgroundColor = UIColor.red
    }
    

    如果您不提供 else 语句,您很可能会在其他单元格中看到另一种红色。

    【讨论】:

    • 这已经在我的 IBAciton func btnTypeSelected 的单元格中并且它不起作用......这就是为什么我试图将它放在视图控制器中的 objc func 中以查看我是否得到了更好的结果
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多