【问题标题】:Updating label in UITableViewCell with UIStepper in Swift在 Swift 中使用 UIStepper 更新 UITableViewCell 中的标签
【发布时间】:2021-09-18 00:51:27
【问题描述】:

我是 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 日更新):

食品

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

【问题讨论】:

标签: ios swift xcode uitableview uistepper


【解决方案1】:

单元配置:

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

【讨论】:

    【解决方案2】:

    最初FoodTableViewCell 是更改UIStepper 值的唯一目标(查看@IBActionFoodTableViewCell)。

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

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

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

    要解决的问题:

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

    这会让您更好地了解为什么会这样。使用这些更改更新您的问题,以防您仍然没有想要的内容。


    更新

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

    【讨论】:

    • 感谢您的回复。我刚刚删除了您在代码中提到的两件事,这使我的 UIStepper 值恢复为 1,而 servingLabels 显示不同的数字。由于 NotificationCenter 没有帮助,如何将标签和步进值连接在一起?是否建议实现另一个委托?
    • 请在实施建议的更改后更新您的问题描述以显示最新更新的代码。
    • 我刚刚更新了问题描述。谢谢。
    • 查看更新
    • 显然,我把事情弄得太复杂了。感谢您的热心帮助!
    【解决方案3】:

    请检查 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
    }
    

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

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-17
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    相关资源
    最近更新 更多