使用 Swift 中的 UIStepper 更新 UITableViewCell 中的标签

问题描述

我是 Swift 初学者,我正在尝试制作一个用于订购食物的简单应用。用户可以通过设置食物namepriceserving添加新订单。添加订单后,该订单将在 tableView 上显示FoodTableViewCell,并且用户可以在每个单元格中使用名为 stepper 的 UIStepper 更改服务。每个订单都是一个 FoodItem,存储在一个名为 foodList 的数组中,您可以在 ShoppingListVC 的 tableView 中看到列出的所有订单。

我的问题是:当我在 stepper 上按“+”或“-”按钮时,我的 servingLabel 没有更改为相应的值。我尝试使用NotificationCenter 将服务值传递给 stepper,并在 food.serving 之后使用委托模式将新值存储回 stepperValueChanged。但是,似乎仍然存在一些错误。在网上浏览了很多解决方案后,我有点困惑。任何帮助表示赞赏。

更新

删除NotificationCenteraddTarget 相关方法作为@Tarun Tyagi 的建议。现在我的 UIStepper 值变回 1,而servingLabels 显示不同数量的服务。由于 NotificationCenter 没有帮助,我如何将标签和步进值连接在一起?是否建议实现另一个委托?

这是我的代码(7 月 8 日更新):

食品

class FoodItem: Equatable {
    
    static func == (lhs: FoodItem,rhs: FoodItem) -> Bool {
        return lhs === rhs
    }
    
    var name: String
    var price: Int
    var serving: Int
    var foodID: String
    
    init(name: String,price: Int,serving: Int) {
        self.name = name
        self.price = price
        self.serving = serving
        self.foodID = UUID().uuidString
    }
}

视图控制器

import UIKit

class ShoppingListVC: UIViewController,UITableViewDataSource,UITableViewDelegate {
    
    var foodList = [FoodItem]()
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.delegate = self
        tableView.dataSource = self
       
        ...
        
        for i in 1...5 {
            let testItem = FoodItem(name: "Food\(i)",price: Int.random(in: 60...100),serving: Int.random(in: 1...10))
            self.foodList.append(testItem)
        }
    }
    
    // MARK: - Table view data source
    
    ...
    
    func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "foodCell",for: indexPath) as! FoodTableViewCell
        
        let food = foodList[indexPath.row]
        cell.nameLabel.text = food.name
        cell.priceLabel.text = "$\(String(food.price)) / serving"
        cell.servingLabel.text = "\(String(food.serving)) serving"
        
        cell.stepper.tag = indexPath.row
        
        cell.delegate = self

        return cell
    }
}

// MARK: - FoodTableViewCellDelegate Method.

extension ShoppingListVC: FoodTableViewCellDelegate {
    
    func stepper(_ stepper: UIStepper,at index: Int,didChangeValueto newValue: Double) {
        let indexPath = IndexPath(item: index,section: 0)
        guard let cell = tableView.cellForRow(at: indexPath) as? FoodTableViewCell else { return }
        let foodToBeUpdated = foodList[indexPath.row]
        
        print("foodToBeUpdated.serving: \(foodToBeUpdated.serving)")
        
        foodToBeUpdated.serving = Int(newValue)
        print("Value changed in VC: \(newValue)")
        
        cell.servingLabel.text = "\(String(format: "%.0f",newValue)) serving"
    }
}

TableViewCell

import UIKit
    
    protocol FoodTableViewCellDelegate: AnyObject {
      func stepper(_ stepper: UIStepper,didChangeValueto newValue: Double)
    }
    
    class FoodTableViewCell: UITableViewCell {
        
        @IBOutlet weak var nameLabel: UILabel!
        @IBOutlet weak var priceLabel: UILabel!
        @IBOutlet weak var servingLabel: UILabel!
        @IBOutlet weak var stepper: UIStepper!
        
        weak var delegate: FoodTableViewCellDelegate?
        
        @IBAction func stepperValueChanged(_ sender: UIStepper) {
            sender.minimumValue = 1
            servingLabel.text = "\(String(format: "%.0f",sender.value)) serving"
            // Pass the new value to ShoppingListVC and notify which cell to update using tag.
            print("sender.value: \(sender.value)")
            delegate?.stepper(stepper,at: stepper.tag,didChangeValueto: sender.value)
        }
        
        override func awakeFromNib() {
            super.awakeFromNib()
            print(stepper.value)
        }
    }

解决方法

单元配置:

  protocol FoodTableViewCellDelegate: AnyObject {
     func stepper(sender: FoodTableViewCell)
    }

@IBAction func stepperButtonTapped(sender: UIStepper) {
    delegate?.stepperButton(sender: self)
    stepperLabel.text = "\(Int(countStepper.value))"
}

控制器配置:

cellForRow:

    cell.countStepper.value = Double(foodList[indexPath.row].serving);
    cell.stepperLabel.text = "\(Int(cell.countStepper.value))"

委托方法:

func stepperButton(sender: FoodTableViewCell) {
    if let indexPath = tableView.indexPath(for: sender){
        print(indexPath)
        foodList[sender.tag].serving = Int(sender.countStepper.value)
    }
}
,

最初 FoodTableViewCellUIStepper 值更改的唯一目标(查看 @IBAction 中的 FoodTableViewCell)。

当您将单元格出列以在屏幕上显示时,您调用 -

cell.stepper.addTarget(self,action: #selector(stepperValueChanged(_:)),for: .valueChanged)

这会导致您的 ShoppingListVC 实例被添加为附加目标每次执行 cellForRow 调用。

需要解决的问题:

  1. 从两个类中删除所有与 NotificationCenter 相关的代码。
  2. 同时删除 cell.stepper.addTarget() 行。

这会让您更好地了解为什么会以这种方式发生。如果您仍然没有想要的东西,请使用这些更改更新您的问题。


更新

// Inside cellForRow
cell.stepper.value = food.serving
,

请检查 value stepper pod,它会对您有所帮助:Value stepper

集成 value stepper pod 并使用以下代码进行基本实现。

import ValueStepper

let valueStepper: ValueStepper = {
let stepper = ValueStepper()
stepper.tintColor = .whiteColor()
stepper.minimumValue = 0
stepper.maximumValue = 1000
stepper.stepValue = 100
return stepper
}()

override func viewDidLoad() {
super.viewDidLoad()       
valueStepper.addTarget(self,action: "valueChanged:",forControlEvents: .ValueChanged)
}

@IBAction func valueChanged1(sender: ValueStepper) {
// Use sender.value to do whatever you want
}

它简化了自定义步进器植入。在table tableview中取出value stepper view并使用它。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...