如何从 TextFields 中获取值并将该值附加到 Swift 中 TableViewCell 的 DataModel 中?

How to get value from TextFields and append that value in DataModel in TableViewCell in Swift?

提问人:SwiftNewbie 提问时间:10/28/2023 更新时间:10/28/2023 访问量:28

问:

我有一个包含货币数组的 TableView。数组可以有多个元素,并且 TableView 单元格包含一个 TextField。

enter image description here

用户可能会也可能不会为所有货币添加价格。我已经实现了textFieldDidEndEditing委托方法来获取textField的值。这是我的 CellForRowAt:


struct PriceModel {
    var country : CountryListData?
    var price : String?
    var cancel : Bool?
    
    init(country: CountryListData? = nil, price: String? = nil, cancel: Bool? = nil) {
        self.country = country
        self.price = price
        self.cancel = cancel
    }
}


// MARK: - Variables
    var priceArray = [PriceModel]()
    var countryArray = [CountryListData]()
    var onSaveClick : (([PriceModel])->Void)?
    var textFieldValues: [IndexPath: String] = [:]



func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "PriceTableViewCell", for: indexPath) as! PriceTableViewCell
        let obj = self.countryArray[indexPath.row]
        cell.editPriceCodeLabel.text = obj.iso_code ?? ""
        cell.editPriceTextField.tag = indexPath.row
        cell.editPriceTextField.delegate = self
        if let value = self.textFieldValues[indexPath] {
            cell.editPriceTextField.text = value
            print("value --> \(value) at index --> \(indexPath.row)")
            let price = PriceModel(country: obj, price: value, cancel: true)
            print("price --> \(price)")
            self.priceArray.append(price)
            print("priceArray --> \(self.priceArray)")
        }
        
        cell.selectionStyle = .none
        return cell
    }

// MARK: - TextField Delegate
extension PriceScreen: UITextFieldDelegate {
    func textFieldDidEndEditing(_ textField: UITextField) {
        let indexPath = IndexPath(row: textField.tag, section: 0)
        self.textFieldValues[indexPath] = textField.text ?? ""
        print("self.textFieldValues --> \(self.textFieldValues)")
        self.retailPriceTableView.reloadRows(at: [indexPath], with: .automatic)
    }
}

我的代码有问题。我注意到,如果我不关闭键盘,文本字段中的值就不会添加到变量中。我不确定我是否使用正确的方法来获取值。有人可以帮助我或提供指导吗?任何类型的援助将不胜感激。self.textFieldValues[indexPath]

谢谢!

iOS Swift UITableView UITextField

评论


答:

1赞 DonMag 10/28/2023 #1

无论是分配文本字段,还是使用带有闭包的更“Swifty”方法,您都希望在编辑字段时更新数据,而不是在 ..delegatetextFieldDidEndEditing

因此,在您的 中,我们将声明关闭:PriceTableViewCell

var priceClosure: ((PriceTableViewCell, String) -> ())?

然后,我们将向文本字段添加目标操作:

textField.addTarget(self, action: #selector(didEdit(_:)), for: .editingChanged)

并且,此选择器/func:

@objc func didEdit(_ sender: UITextField) {
    // inform the controller that the text field text was edited
    priceClosure?(self, textField.text ?? "")
}

在控制器中,我们将分配闭包:cellForRowAt

// add the closure
c.priceClosure = { [weak self] aCell, aStr in
    guard let self = self,
          let idx = self.tableView.indexPath(for: aCell)
    else { return }
    self.myData[idx.row].price = aStr
    self.updateTotal()
}

该关闭将在编辑字段时调用......无需等待用户点击其他字段或手动关闭键盘。

这是一个快速完整的示例...


简单的标签和文本字段单元格类 - 带有闭包:

class PriceTableViewCell: UITableViewCell {
    
    var priceClosure: ((PriceTableViewCell, String) -> ())?
    
    let label = UILabel()
    let textField = UITextField()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        [label, textField].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            contentView.addSubview(v)
        }
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            label.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            
            textField.topAnchor.constraint(equalTo: g.topAnchor),
            textField.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            textField.bottomAnchor.constraint(equalTo: g.bottomAnchor),
            textField.widthAnchor.constraint(equalToConstant: 120.0),
            
        ])
        
        textField.borderStyle = .roundedRect
        textField.keyboardType = .decimalPad
        textField.addTarget(self, action: #selector(didEdit(_:)), for: .editingChanged)
    }
    @objc func didEdit(_ sender: UITextField) {
        // inform the controller that the text field text was edited
        priceClosure?(self, textField.text ?? "")
    }
    
}

简化价格型号

struct PriceModel {
    var name: String = ""
    var price: String = ""
}

示例控制器类 - 顶部带有“运行总计”标签:

class PriceScreenVC: UIViewController {
    
    var myData: [PriceModel] = [
        PriceModel(name: "A", price: ""),
        PriceModel(name: "B", price: ""),
        PriceModel(name: "C", price: ""),
        PriceModel(name: "D", price: ""),
    ]
    
    let runningTotalLabel = UILabel()
    let tableView = UITableView()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        [runningTotalLabel, tableView].forEach { v in
            v.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(v)
        }
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            runningTotalLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
            runningTotalLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            runningTotalLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            
            tableView.topAnchor.constraint(equalTo: runningTotalLabel.bottomAnchor, constant: 8.0),
            tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -8.0),
            
        ])
        
        tableView.register(PriceTableViewCell.self, forCellReuseIdentifier: "priceCell")
        tableView.dataSource = self
        tableView.delegate = self
        
        runningTotalLabel.textAlignment = .center
        runningTotalLabel.text = "Total: 0"
    }

    func updateTotal() {
        var t: Double = 0
        myData.forEach { p in
            if let val = Double(p.price) {
                t += val
            }
        }
        runningTotalLabel.text = "Total: \(t)"
    }
}


extension PriceScreenVC: UITableViewDataSource, UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let c = tableView.dequeueReusableCell(withIdentifier: "priceCell", for: indexPath) as! PriceTableViewCell
        
        c.label.text = myData[indexPath.row].name
        c.textField.text = myData[indexPath.row].price

        // add the closure
        c.priceClosure = { [weak self] aCell, aStr in
            guard let self = self,
                  let idx = self.tableView.indexPath(for: aCell)
            else { return }
            self.myData[idx.row].price = aStr
            self.updateTotal()
        }
        
        return c
    }
    
}

运行时看起来像这样:

enter image description here