简体   繁体   English

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

[英]Updating label in UITableViewCell with UIStepper in Swift

I'm a Swift beginner and I'm trying to make a simple app for ordering food.我是 Swift 初学者,我正在尝试制作一个简单的应用程序来订购食物。 The user could add a new order by setting food name , price and serving .用户可以通过设置食品namepriceserving来添加新订单。 After adding an order, that order will be shown on the tableView as a FoodTableViewCell , and the user could change the serving with an UIStepper called stepper in each cell.添加订单后,该订单将作为FoodTableViewCell显示在 tableView 上,用户可以在每个单元格中使用名为stepper的 UIStepper 更改服务。 Each order is a FoodItem stored in an array called foodList , and you can see all orders listed in a tableView in ShoppingListVC .每个订单都是一个FoodItem存储在一个名为foodList的数组中,您可以在ShoppingListVC的 tableView 中看到列出的所有订单。

My problem is: When I press "+" or "-" button on stepper , my servingLabel doesn't change to corresponding value.我的问题是:当我在stepper上按“+”或“-”按钮时,我的servingLabel不会更改为相应的值。 I tried to use NotificationCenter to pass serving value to stepper , and store new value back to food.serving after stepperValueChanged with delegate pattern.我尝试使用NotificationCenter将服务值传递给stepper ,并在stepperValueChanged与委托模式后将新值存储回food.serving However, there still seems to be some bugs.但是,似乎仍然存在一些错误。 I've been kind of confused after browsing lots of solutions on the Internet.在网上浏览了很多解决方案后,我有点困惑。 Any help is appreciated.任何帮助表示赞赏。

Update更新

I removed NotificationCenter and addTarget related methods as @Tarun Tyagi 's suggestion.我删除NotificationCenteraddTarget相关的方法为@Tarun特亚吉的建议。 Now my UIStepper value turns back to 1 whereas the servingLabels are showing different numbers of serving.现在我的 UIStepper 值变回 1,而servingLabels 显示不同数量的服务。 Since NotificationCenter doesn't help, how can I connect the label and stepper value together?由于 NotificationCenter 没有帮助,我如何将标签和步进值连接在一起? Is it recommended to implement another delegate?是否建议实施另一个委托?

Here are my codes(Updated on July 8):这是我的代码(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)
        }
    }

Cell Config:单元配置:

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

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

Controller Config:控制器配置:

cellForRow:单元格:

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

Delegate Method:委托方式:

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

Initially FoodTableViewCell is the ONLY target for UIStepper value changed (looking at @IBAction inside FoodTableViewCell ).最初FoodTableViewCellUIStepper值更改的唯一目标(查看@IBAction FoodTableViewCell )。

When you dequeue a cell to display on screen, you call -当您将单元格出列以在屏幕上显示时,您调用 -

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

which causes your ShoppingListVC instance to be added as an additional target every time a cellForRow call is executed.这会导致每次执行cellForRow调用将您的ShoppingListVC实例添加为附加目标。

Things to fix :需要解决的问题:

  1. Remove all of your NotificationCenter related code from both classes.从两个类中删除所有与NotificationCenter相关的代码。
  2. Remove cell.stepper.addTarget() line as well.也删除cell.stepper.addTarget()行。

This would give you a better idea of why it is happening this way.这会让您更好地了解为什么会以这种方式发生。 Update your question with these changes in case you still don't have what you want.如果您仍然没有想要的东西,请使用这些更改更新您的问题。


UPDATE更新

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

Please check value stepper pod it will help you: Value stepper请检查 value stepper pod 它将帮助您: Value stepper

Integrate value stepper pod and use below code for basic implementation.集成 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
}

Its simplify custom stepper implantation.Take outlet of value stepper view in table tableview and use it.它简化了自定义步进器植入。在表格tableview中取出值步进器视图并使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM