Swift - Увеличить метку с помощью Stepper в ячейке TableView

Еще один новичок Swift здесь. Мне просто нужен Stepper в каждой из моих ячеек TableView, который увеличивает метку в той же ячейке.

Я нашел пару вопросов по этой теме, но они включают в себя другие элементы, и я не смог извлечь основную концепцию.

Быстрое пошаговое действие, которое изменяет UITextField и UILabel внутри одного и того же ячейка

Степпер в ячейке tableview (быстро)

До сих пор я подключал IBOutlets для моего Label и Stepper, а также IBAction для моего Stepper в моем классе ячеек.

class BuyStatsCell: UITableViewCell{

    //these are working fine

    @IBOutlet weak var category: UILabel!
    @IBOutlet weak var average: UILabel!
    @IBOutlet weak var price: UILabel!


    //Outlet for Label and Stepper - How do I make these work?

    @IBOutlet weak var purchaseAmount: UILabel!
    @IBOutlet weak var addSubtract: UIStepper!

    //Action for Stepper - And this?

    @IBAction func stepperAction(_ sender: UIStepper) {
        self.purchaseAmount.text = Int(sender.value).description

    }

}

И я понимаю концепцию повторного использования ячейки в cellForRowAt indexPath

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "BuyStatsTabCell", for: indexPath) as! BuyStatsCell

        cell.isUserInteractionEnabled = false

 //these are working 

        cell.category.text = categories[indexPath.row]
        cell.price.text = String(prices[indexPath.row])
        cell.average.text = String(averages[indexPath.row])

//but is there something I need to add here to keep the correct Stepper and Label for each class?

    return cell
}

Один из уже заданных вопросов включает в себя протокол и другую функцию в ViewController, подобную этой.

protocol ReviewCellDelegate{
    func stepperButton(sender: ReviewTableViewCell)
}

func stepperButton(sender: ReviewTableViewCell) {
    if let indexPath = tableView.indexPathForCell(sender){
        print(indexPath)
    }
}

Я не знаю, тот ли это подход, который я должен использовать. Я ищу самое простое решение, но у меня возникают проблемы с соединением частей.

Любая помощь приветствуется. Спасибо.


person Louis Sankey    schedule 18.03.2017    source источник
comment
Почему бы вам не использовать единый исходный массив с моделями продуктов и не добавлять цену, среднее значение и категорию в качестве свойств? Затем, когда вы меняете модели и перезагружаете измененные модели, они должны быть постоянными. Я не совсем уверен, что проблема в настойчивости.   -  person silentBob    schedule 18.03.2017
comment
Итак, чего вы пытаетесь достичь, так это позволить степперу увеличивать/уменьшать значение текущего объекта на основе строки categories, верно?   -  person Ahmad F    schedule 18.03.2017
comment
Спасибо вам обоим за ответ. Я добавил несколько комментариев в свой код для пояснения. Категория, Средняя и Цена работают нормально. PurchaseAmount — это метка, которую я пытаюсь обновить с помощью Stepper. Каждая строка в моем списке имеет сумму покупки и степпер, используемый для сложения или вычитания.   -  person Louis Sankey    schedule 18.03.2017
comment
Как предложил @vadian, я бы рекомендовал, чтобы источник данных массива был только одним, содержащим модели, а не чтение из categories, prices и averages. Возможно, проверка этих вопросов и ответов поможет вам понять это.   -  person Ahmad F    schedule 18.03.2017


Ответы (2)


Самое простое решение (упрощенное):

  • Создайте модель BuyStat со свойством purchaseAmount (крайне важно, чтобы это был класс).
    Настоятельно не рекомендуется использовать несколько массивов в качестве источника данных.

    class BuyStat {
    
        var purchaseAmount = 0.0
    
        init(purchaseAmount : Double) {
            self.purchaseAmount = purchaseAmount
        }
    }
    
  • В контроллере представления создайте массив источника данных

    var stats = [BuyStat]()
    
  • В viewDidLoad создайте несколько экземпляров и перезагрузите табличное представление.

    stats = [BuyStat(purchaseAmount: 12.0), BuyStat(purchaseAmount: 20.0)]
    tableView.reloadData()
    
  • В пользовательской ячейке создайте свойство buyStat для хранения текущего элемента источника данных с наблюдателем для обновления степпера и метки, когда установлено buyStat

    class BuyStatsCell: UITableViewCell {
    
        @IBOutlet weak var purchaseAmount: UILabel!
        @IBOutlet weak var addSubtract: UIStepper!
    
        var buyStat : BuyStat! {
            didSet {
                addSubtract.value = buyStat.purchaseAmount
                purchaseAmount.text = String(buyStat.purchaseAmount)
            }
        }
    
        @IBAction func stepperAction(_ sender: UIStepper) {
            buyStat.purchaseAmount = sender.value
            self.purchaseAmount.text = String(sender.value)
        }
    }
    
  • В cellForRowAtIndexPath получите элемент источника данных и передайте его в ячейку

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "BuyStatsTabCell", for: indexPath) as! BuyStatsCell
        cell.buyStat = stats[indexPath.row]
        return cell
    }
    

Магия: при нажатии на степпер метка, а также массив источника данных будут обновлены. Таким образом, даже после прокрутки ячейка всегда будет получать актуальные данные.

Таким образом, вам не нужны протоколы или закрытие обратного вызова. Важно только, чтобы модель была классом и имела семантику ссылочного типа.

person vadian    schedule 18.03.2017
comment
Я думаю, что этот подход лучше, чем обработка действия степпера на уровне ViewController, распознавая текущий степпер - добавляя тег для каждого, редактируя значение источника данных массива и вызывая reloadData(), я нахожу его более несвязанным и логично, это правильно? :) - person Ahmad F; 18.03.2017
comment
Спасибо за этот отличный ответ. Я уверен, что смогу реализовать на основе этого. Итак, когда вы говорите «stats = [BuyStat (purchaseAmount: 12.0), BuyStat (purchaseAmount: 20.0)] tableView.reloadData ()», это создает две строки списка с начальными значениями 12 и 20 для PurchaseAmount? Затем использовать степпер, чтобы увеличить или уменьшить эту сумму? - person Louis Sankey; 18.03.2017
comment
То есть наиболее значительным преимуществом является ссылка на элемент источника данных, поэтому представление и модель обновляются одновременно. @ithinkthereforeIprogr'am' Да, именно так. - person vadian; 18.03.2017
comment
У меня все еще есть проблемы с тем, чтобы Stepper вообще реагировал. Не знаю, что я делаю неправильно, поскольку я несколько раз пытался повторно подключить розетку Stepper и действие. :-/ Я поместил оператор печати в свой IBAction, но он не работает. Вот пара скриншотов i.stack.imgur.com/zpnvt.png i.stack.imgur.com/J6p7x.png - person Louis Sankey; 19.03.2017
comment
Что, если у меня есть значение по умолчанию, такое как priceLabel.text = 15, и я хочу увеличить это значение с помощью себя для каждого клика на степпер? (например, 2 клика назначаются 15 + 15 = 30) - person Emre Değirmenci; 06.03.2019
comment
@EmreDeğirmenci Настройте stepValue в шаговом экземпляре. - person vadian; 06.03.2019
comment
@EmreDeğirmenci В Interface Builder выберите степпер, нажмите ⌥⌘4, чтобы открыть инспектор атрибутов, и установите для Step значение 15. - person vadian; 06.03.2019
comment
@EmreDeğirmenci Пожалуйста, задайте новый вопрос. - person vadian; 07.03.2019
comment
Мне не нужно было создавать модель данных-оболочку. Вместо этого я использовал массив Int и создал ссылку IBAction на степпер в своем ViewController и каждый раз вызывал reloadData. При создании ячеек я обновляю свой массив, содержащий величины шагового двигателя, на основе значения в метке для этой ячейки. - person btrballin; 23.04.2019

ПРИМЕЧАНИЕ. Класс MY Cell просто нормальный. Все изменения в классе viewcontroller.

class cell: UITableViewCell {

    @IBOutlet weak var ibAddButton: UIButton!
    @IBOutlet weak var ibStepper: UIStepper!
    @IBOutlet weak var ibCount: UILabel!
    @IBOutlet weak var ibLbl: UILabel!
}

1. определить пустой массив целых чисел [Int]()

переменная countArray = [Int]()

2.добавьте countArray со всеми нулями с количеством данных, которые вы хотите заполнить в табличном представлении.

 for arr in self.responseArray{
        self.countArray.append(0)
   }

3.в ячейке для строки в

func tableView(_ tableView: UITableView, cellForRowAt indexPath:
 IndexPath) -> UITableViewCell {

         let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! cell
         let dict = responseArray[indexPath.row] as? NSDictionary ?? NSDictionary()
         cell.ibLbl.text = dict["name"] as? String ?? String()
         if countArray[indexPath.row] == 0{
             cell.ibAddButton.tag = indexPath.row
             cell.ibStepper.isHidden = true
             cell.ibAddButton.isHidden = false
             cell.ibCount.isHidden = true
             cell.ibAddButton.addTarget(self, action: #selector(addPressed(sender:)), for: .touchUpInside)
         }else{
             cell.ibAddButton.isHidden = true
             cell.ibStepper.isHidden = false
             cell.ibStepper.tag = indexPath.row
             cell.ibCount.isHidden = false
             cell.ibCount.text = "\(countArray[indexPath.row])"
             cell.ibStepper.addTarget(self, action: #selector(stepperValueChanged(sender:)), for: .valueChanged)}
    return cell
     }

4.объектные функции

 @objc func stepperValueChanged(sender : UIStepper){
     if sender.stepValue != 0{
         countArray[sender.tag] = Int(sender.value)
     }
     ibTableView.reloadData()
 }
 @objc func addPressed(sender : UIButton){

     countArray[sender.tag] = 1//countArray[sender.tag] + 1
     ibTableView.reloadData()
 }
person suraj jadhav    schedule 13.11.2019