如何处理uitaiteViewCell中按钮的按钮操作?

发布于 2025-01-22 15:46:05 字数 1465 浏览 3 评论 0原文

我正在从事一个购物应用程序项目,客户可以在其中浏览产品并将其添加到购物车中,但是很难弄清楚如何处理TableViewCell中的按钮按钮。我希望它能工作的方式是,按下空圆按钮时,图像将带有选中标记的圆圈更改为填充的圆圈,并且该单元格中的产品被添加到客户的“购物车”中。 “购物车”由两个阵列产品数量 组成。

这是表观视图的样子:

”我的UI的图像“

这是我到目前为止的代码:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 
UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "ProductToBuyCell") as! ProductToBuyCell
    
    //Configure the Selection Button
    cell.selectButton.tag = indexPath.row
    cell.selectButton.addTarget(self, action: #selector(ItemSelected), for: .touchUpInside)
    let product = productsArray[indexPath.row]
    //configure cell
    cell.productImg.image = product.productPhoto
    cell.productImg.contentMode = .scaleAspectFit
    cell.productName.text = product.Name
    cell.price.text = "$\(product.price)"
    
    return cell
}
// func for when the selectButton is tapped
// tag is equal to indexPath.row
@objc func ItemSelected(sender: UIButton) {
    sender.imageView?.image = UIImage(systemName: "checkmark.circle.fill")
    let product = productsArray[sender.tag]
    newOrder.products.append(product)
    newOrder.quantities.append(1)
}

因此,如果有人可以解释如何正确处理由UITATION VIEWCELL中元素引起的事件,以及如何使按钮图像更改,这将不胜感激。

I'm working on a shopping app project where customers can browse through products and add them to their cart, but am having trouble figuring out how to handle button presses within the tableViewCell. They way I want it to work is that when the empty circle button is pressed, the image changes to a filled circle with a checkmark, and the product within that cell is added to the customers "cart". The "cart" consists of two arrays products and quantities held within my CustomerOrder object.

Here's what the tableView looks like:

image of my UI

Here's my code so far:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 
UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "ProductToBuyCell") as! ProductToBuyCell
    
    //Configure the Selection Button
    cell.selectButton.tag = indexPath.row
    cell.selectButton.addTarget(self, action: #selector(ItemSelected), for: .touchUpInside)
    let product = productsArray[indexPath.row]
    //configure cell
    cell.productImg.image = product.productPhoto
    cell.productImg.contentMode = .scaleAspectFit
    cell.productName.text = product.Name
    cell.price.text = "$\(product.price)"
    
    return cell
}
// func for when the selectButton is tapped
// tag is equal to indexPath.row
@objc func ItemSelected(sender: UIButton) {
    sender.imageView?.image = UIImage(systemName: "checkmark.circle.fill")
    let product = productsArray[sender.tag]
    newOrder.products.append(product)
    newOrder.quantities.append(1)
}

So if someone could please explain how to properly handle events that are caused by elements within a UITableViewCell and how to get the buttons image to change, that would be very much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

山川志 2025-01-29 15:46:05

uibutton's imageView是只读的 - 要更新其映像,您应该使用setimage。请注意,您需要跟踪行的选择状态,否则选择状态将在单元重新加载时重置(例如,滚动并回到视图中)。也大概您还需要处理取消按钮的情况。

另外,由于您仅在单元​​格中的uibutton上处理选择,因此点击单元格不会对按钮的状态产生任何影响。取而代之的是,您可以实现tableView(_:didSelectrowat:)并在此处处理选择,并且只有一个简单的uiimageView而不是uibutton uibutton 细胞。您也可以考虑使用

uitaiteView还具有,因此,如果您将其打开,可以为您跟踪所选的单元格,而您只需要相应地更新单元格的外观即可。

至于使用tag来找出单元格索引,这是真的,这不是很健壮,但不是问题。绝对值得在上面的评论中查看链接的问题,以了解有关此问题的一些良好讨论。

是的,如果您要坚持使用这种方法,则至少应该在添加新的动作之前删除任何现有动作以避免重复事件,例如button.removetarget(nil,action:nil:nil,for:.Allelevents)

UIButton's imageView is read-only — to update its image you should use setImage. Note you'll need to keep track of the selection state of the rows or else the selection state will be reset whenever the cell reloads (e.g. it scrolls out and back into view). Also presumably you'll want to handle the case where the button is deselected.

Also, since you're only handling the selection on the UIButton in the cell, tapping the cell will not have any effect on the button's state. You could instead implement tableView(_:didSelectRowAt:) and handle the selection there, and just have a simple UIImageView instead of a UIButton in your cell. You could also consider using the accessoryView.

UITableView also has built-in support for multiple selection, so if you turn that on it can keep track of the selected cells for you, and you just need to update the appearance of the cells accordingly.

As for using the tag to figure out the cell index, it's true it isn't very robust but that wasn't the question. Definitely worth checking out the linked question in the comments above for some good discussion around that.

And yes, if you're going to stick with this approach you should at least remove any existing actions before adding a new one to avoid duplicate events, e.g. button.removeTarget(nil, action: nil, for: .allEvents).

昔梦 2025-01-29 15:46:05

我假设您的产品模型就是这样。

struct Product {
    let name: String
    let photo: UIImage!
    let price: Double
}

跟踪所选产品。您需要保留细胞的状态。创建另一个类似的模型

struct ProductSelection {
    let product: Product!
    var isSelected: Bool = false
}

为 @ paulw11提到的是“ tag不是一个很好的解决方案,因为默认值为0,如果重新排序行,它将断开”,您可以使用委托模式来获取所选产品指数。

创建productTobuycell的协议。

protocol ProductToBuyCellDelegate: AnyObject {
    func selectedCell(sender: ProductToBuyCell)
}

将委托属性添加到单元格中。

weak var delegate: ProductToBuyCellDelegate?

还要添加iboutletibaction producttobuycell中的按钮。

@IBOutlet weak var checkButton: UIButton!


@IBAction func buttonPressed(_ sender: UIButton) {
    delegate?.selectedCell(sender: self)
}

然后在单元格中添加SelectionProduct属性,并设置uilabel的文本和uiimage的图像使用属性观察者didset

var productSelection: ProductSelection? {
    didSet {
        guard let productSelection = productSelection else { return }

        self.productNameLabel.text = productSelection.product.name
        self.priceLabel.text = "$\(productSelection.product.price)"
        self.productImg.image = productSelection.product.photo
        
        if productSelection.isSelected {
            checkButton.setImage(UIImage(systemName: "checkmark.circle.fill"), for: .normal)
        } else {
            checkButton.setImage(UIImage(systemName: "circle"), for: .normal)
        }
    }
}

修改uiimage的外观awakefromnib()方法中

override func awakeFromNib() {
    super.awakeFromNib()
    
    self.productImg.contentMode = .scaleAspectFit
}

,然后修改cellforrowat如下所示。在这里,productSelectionArrayproductsection不是产品的数组。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ProductToBuyCell") as! ProductToBuyCell
    cell.productSelection = productSelectionArray[indexPath.row]
    cell.delegate = self
    return cell
}

现在,确认委托 producttobuycell to view> view controller。在这里,首先,我更改所选单元格的状态,然后使用filtermap 函数在productsselectionarray中检索所有选定的产品。然后重新加载行更新UI。

extension ViewController: ProductToBuyCellDelegate {
    func selectedCell(sender: ProductToBuyCell) {
        guard let tappedIndexPath = tableView.indexPath(for: sender) else { return }

        productSelectionArray[tappedIndexPath.row].isSelected.toggle()

        let selectedProducts = productSelectionArray.filter{ $0.isSelected }.map { (productSelection: ProductSelection) -> Product in
            return productSelection.product
        }

        tableView.reloadRows(at: [tappedIndexPath], with: .none)
    }
}

根据您的UI,似乎所有选定的产品数量都是一个,因此您不必将另一个数组维护数量。

I assume your Product model is like this.

struct Product {
    let name: String
    let photo: UIImage!
    let price: Double
}

To keep track of the selected product. You need to preserve the state of the cell. Create another model like this

struct ProductSelection {
    let product: Product!
    var isSelected: Bool = false
}

As @ Paulw11 mentioned that "tag isn't a great solution since the default is 0 and it will break if rows are reordered", you can use delegate pattern to get the selected product index.

Create a protocol of the ProductToBuyCell.

protocol ProductToBuyCellDelegate: AnyObject {
    func selectedCell(sender: ProductToBuyCell)
}

Add a delegate property to cell.

weak var delegate: ProductToBuyCellDelegate?

Also add an IBOutlet and IBAction of the button in ProductToBuyCell.

@IBOutlet weak var checkButton: UIButton!


@IBAction func buttonPressed(_ sender: UIButton) {
    delegate?.selectedCell(sender: self)
}

Then add a selectionProduct property in the cell and set text of UILabel and image of UIImage using property observer didSet

var productSelection: ProductSelection? {
    didSet {
        guard let productSelection = productSelection else { return }

        self.productNameLabel.text = productSelection.product.name
        self.priceLabel.text = "$\(productSelection.product.price)"
        self.productImg.image = productSelection.product.photo
        
        if productSelection.isSelected {
            checkButton.setImage(UIImage(systemName: "checkmark.circle.fill"), for: .normal)
        } else {
            checkButton.setImage(UIImage(systemName: "circle"), for: .normal)
        }
    }
}

Modify the appearence of UIImage in awakeFromNib() method

override func awakeFromNib() {
    super.awakeFromNib()
    
    self.productImg.contentMode = .scaleAspectFit
}

Then modify the cellForRowAt method like below. Here, productSelectionArray is an array of ProductSection not Product.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ProductToBuyCell") as! ProductToBuyCell
    cell.productSelection = productSelectionArray[indexPath.row]
    cell.delegate = self
    return cell
}

Now confirm the delegate of ProductToBuyCell to ViewController. Here, at first I change the state of the selected cell and then retrieve all the selected products using filter and map function in productSelectionArray. And then reload the row to update UI.

extension ViewController: ProductToBuyCellDelegate {
    func selectedCell(sender: ProductToBuyCell) {
        guard let tappedIndexPath = tableView.indexPath(for: sender) else { return }

        productSelectionArray[tappedIndexPath.row].isSelected.toggle()

        let selectedProducts = productSelectionArray.filter{ $0.isSelected }.map { (productSelection: ProductSelection) -> Product in
            return productSelection.product
        }

        tableView.reloadRows(at: [tappedIndexPath], with: .none)
    }
}

According to your UI it seems that all the selected products quantity is one, so you don't have to maintain another array for quantity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文