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

Updating label in UITableViewCell with UIStepper in Swift

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

中的 tableView 中看到列出的所有订单

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

更新

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

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

FoodItem

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

ViewController

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, at index: Int, 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 值更改的唯一目标(查看 FoodTableViewCell 中的 @IBAction)。

当您使一个单元格出队显示在屏幕上时,您调用 -

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

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

需要解决的问题:

  1. 从 类.
  2. 中删除所有 NotificationCenter 相关代码
  3. 也删除 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
}

它简化了自定义步进器 implantation.Take 价值步进器视图的出口 table table查看并使用它。