如何防止单元在另一个单元中镜像按钮按下的动作? [英] How to prevent cells from mirroring button pressed action in another cell?

查看:57
本文介绍了如何防止单元在另一个单元中镜像按钮按下的动作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在表视图的单元格中有3个按钮,它们位于@IBAction按钮集合中,因此当选择一个按钮时,它将按钮颜色从蓝色变为红色,并取消选择先前按下的按钮回到蓝色。代码执行这些操作时可以正常工作

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. the code works fine when performing those actions

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

the problem that im having is that when a button is selected in one cell, the exact same button will be selected in another cell as shown below▼

到目前为止,我没有尝试过,我认为可行的是我在视图控制器中创建了一个 @objc func,但是我不知道该从哪个ive创建,以防止单元格中的镜像

so far what ive tried isn't working and I think what might work is that I to create an "@objc func" in the view controller but I dont know where to go from what ive created to prevent the "mirroring" in the cells

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

I know that Im close to the solution thank you in advance for any help that you give



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
    }
}


推荐答案

Evelyn,您好!使用委托模式! :)

H e llo, Evelyn! Use delegation pattern! :)

以下是一些帮助您继续前进的解释:

Here are some explanations to help you keep going:


  1. 创建代表您的表格视图内容的模型






我们可以使用哪种模型,代表仅选择一个按钮的状态?枚举可以表示该枚举(将其添加到单独的文件或您的控制器中):


What kind of a model could we use, to represent the state of having only ever a single button selected? An enum can represent that(add it in a separate file or in your controller):

enum ButtonSelectionIdentity {
    case first
    case second
    case third
}

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

Our table view is going to present an array of those enums, in the controller, lets add an instance variable to hold the data, and initialize it with an empty array:

private var elements: [ButtonSelectionIdentity] = []

让我们用该数组填充在您的控制器viewDidLoad函数中,默认为100个元素(默认为选择第一个按钮),

Let's populate this array with 100 elements, defaulting to the first button being selected, in your controller viewDidLoad function, add:

    for i in 0..<100 {
        elements.append(ButtonSelectionIdentity.first)
    }




  1. 确保从模型中更新单元格






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


So now we have a model(an array of ButtonSelectionIdentity), and we want table view controller to reflect that model. To do so, we change the original way of how a controller conformed UITableViewDataSource. We need the new implementation to take the data from the array:

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
    }
}

是,在上面更改之后在我们将更新方法添加到单元格类之前,它不会编译:

Yes, after above change it won't compile, until we add an update method to the cell class:

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个单元格的第一个正方形为红色。

Compile and run, you should see 100 cells having the first square red.


  1. 允许将单元格动作连接至控制器






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


Remove buttonSelected method in your controller class, and remove your btnTypeSelected method of your Cell class, so that we can start over.

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

At this stage, we have an array of elements, that are presented on the table view, inside of the controller. Controller owns it, because it created it. Cells are there to only present the state that the controller has. So, in order to get our cell to update, we need to tell controller, that we are updating. To do that, we can use delegation pattern. Lets create a cell delegate protocol to describe it.

在您的 Cell 类文件中,在<$ c $之前c> Cell类... ,添加:

In your Cell class file, before the class Cell ..., add:

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

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

So this is the delegate we will use to let the controller know about the state change in the cell. Lets add a weak reference to the cell to the delegate. In your Cell, add:

weak var delegate: CellDelegate?

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

Now, conform your controller to the CellDelegate protocol. In your controller class, add:

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

现在我们将其保留为空,并且

for now we will leave it empty, and will finish it later.

现在,控制器可以是单元的委托。让它成为一个!
更新控制器的 cellForRowAt 方法,如下所示:

Now, controller can be a delegate of a cell. Lets make it to be the one! Update the cellForRowAt method of your controller, as follows:

    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
    }

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

Done, we configured our controller to be the cell's delegate! Let's make some use of that!


  1. 在单元格报告其状态更改时,使控制器更新模型






在您的单元格中,分别将每个按钮上的IBAction连接起来:


In your cell, wire up IBActions on each of the buttons separately:

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

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

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

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

Whenever a button is tapped, we want our cell to tell the controller of a state change, for example:

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

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

Implement the other two methods accordingly.

在您的控制器中,让我们重新访问 onCellModelChange 方法。既然对单元格进行了操作,我们需要在 elements 数组中找到一个与该单元格相对应的元素。为此,我们可以使用 tableView -s -indexPath(for:)方法:

In your controller, let's revisit onCellModelChange method. Now that an action on a cell happened, we need to find an element in the elements array, corresponding to that cell. To do that, we can make use of tableView-s -indexPath(for:) method:

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

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

If you run the app, at this stage you should see logs of the indexpaths corresponding to cells that you press the buttons on. Not quite what we need yet.

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

Our table view is only presenting a single section, so we can ignore the section from the index path, and only consider a row, which will be the same as our element index. Lets update the value in the array, using this index:

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
    }
}

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

Now if you run this, you should get the model updated, but the cell's state won't update right away. You can still see it working, if you scroll the cell out of screen, and scroll back again.

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

The last bit is making the cell update right away. How can we do that? Lets just put the updated model back to the cell:

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)
    }
}

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

And this should be it! I didn't test it and didn't compile it :) So if you find any typos, let me know :) Cheers

这篇关于如何防止单元在另一个单元中镜像按钮按下的动作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆