代码之家  ›  专栏  ›  技术社区  ›  Joe

将数据从子VC传回集合视图单元格

  •  1
  • Joe  · 技术社区  · 6 年前

    我有两个 ViewController : MainVC ChildVC 这个 MainVC公司 包括 CollectionView 有5个 cell .每个 单间牢房 分段至 儿童VC .关于此 儿童VC ,您可以选择增加(或减少)计数器的不同项目 儿童VC (计数器仅显示“##选定”。)

    基本上,我只想在 儿童VC 将传回各自的标签上 MainVC公司 被窃听的单元格。例如:如果用户点击 MainVC公司 ,选择 儿童VC ,然后返回到 MainVC公司 ,则第二个单元格上的标签中会有一个“13”。然后,如果用户点击第一个单元格,则在 儿童VC ,然后返回到 MainVC公司 ,第一个单元格上的标签上会有“5”,第二个单元格上的标签上会有“13”。

    我的进度:

    我已经决定委派是适合我的需求的一种解决方案,因为委派可以方便地向VC传递数据或从VC传递数据。我在传递数据时需要帮助 返回 来自 儿童VC A. 集合视图 单间牢房

    我的问题:

    • 除了所选的计数器计数(Int)之外,还应该在 protocol ?(我不确定 indexPath 应传递,以便数据显示在 MainVC公司 ?)
    • MainVC公司 ,如果从 协议 儿童VC 发送到 CollectionViewCell ?或者 MainVC公司 cellForItemAt 方法

    更新时间:

    下面我有一些进展。但它没有按预期工作。

    在下面的代码中,我创建了ViewController(MainVC)和ChildVC。在子VC中,有一个UISlider来模拟所选计数器。我希望将此计数器数据传回各自的MainVC CollectionView单元格。现在的情况是,一旦我更改滑块的值,MainVC CollectionView就会添加一个新的单元格!“清除所有动物”btn需要“归零”所有单元格的滑块数据,但我还没有做到这一点。。

    视图控制器(上面我的问题中的MainVC)

    class ViewController: UIViewController {
    
        var allAnimals = AnimalData.getAllAnimals()
        @IBOutlet weak var mainCV: UICollectionView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            mainCV.dataSource = self
    
        }
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "AnimalSegue" {
                let childVC = segue.destination as! ChildVC
                childVC.delegate = self
    
                if let indexPath = self.mainCV.indexPath(for: sender as! AnimalCollectionViewCell) {
                    let animalData = self.allAnimals[indexPath.item]
                    childVC.animal = animalData
                    childVC.indexPath = indexPath
                }
    
                childVC.allIndexPaths = getAllIndexPaths()
    
            }
        }
    
        func getAllIndexPaths() -> [IndexPath] {
            var indexPaths: [IndexPath] = []
    
            for i in 0..<mainCV.numberOfSections {
                for j in 0..<mainCV.numberOfItems(inSection: i) {
                    indexPaths.append(IndexPath(item: j, section: i))
                }
            }
            return indexPaths
        }
    
    }
    
    
    extension ViewController: DataDelegate {
        func zeroOut(for animalObject: AnimalModel, at indexPath: [IndexPath]) {
            print("ZERO OUT")
            self.mainCV.reloadData()
        }
    
        func updatedData(for animalObject: AnimalModel, at indexPath: IndexPath ) {
            self.allAnimals[indexPath.item] = animalObject
            self.mainCV.reloadItems(at: [indexPath])
        }
    }
    
    extension ViewController: UICollectionViewDataSource {
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return allAnimals.count
        }
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AnimalCell", for: indexPath as IndexPath) as! AnimalCollectionViewCell
            let animal = allAnimals[indexPath.item]
    
            cell.animal = animal
    
            return cell
        }
    }
    

    儿童VC

    class ChildVC: UIViewController {
    
    
        @IBOutlet weak var animalTitleLabel: UILabel!
        @IBOutlet weak var labelCounter: UILabel!
        @IBOutlet weak var sliderLabel: UISlider!
    
        var delegate: DataDelegate?
        var animal: AnimalModel?
        var indexPath: IndexPath?
        var allIndexPaths: [IndexPath]?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            animalTitleLabel.text = animal?.name
            animalTitleLabel.textColor = animal?.color ?? .white
            sliderLabel.value = Float(animal?.amountCounter ?? 0)
            self.labelCounter.text = "\(Int(sliderLabel.value))"
    
        }
    
        @IBAction func closeButtonPressed(_ sender: UIButton) {
            if let delegate = self.delegate,
                let indexPath = self.indexPath,
                let animal = self.animal {
                delegate.updatedData(for: animal, at: indexPath)
            }
            self.dismiss(animated: true, completion: nil)
        }
    
    
        @IBAction func sliderChanged(_ sender: UISlider) {
            let newValue = Int(sender.value)
            labelCounter.text = "\(newValue)"
            self.animal?.amountCounter = newValue
        }
    
        @IBAction func clearAllBtnPressed(_ sender: UIButton) {
            if let delegate = self.delegate,
                let all = self.allIndexPaths,
                var animal = self.animal {
                animal.amountCounter = 0
                delegate.zeroOut(for: animal, at: all)
            }
            self.dismiss(animated: true, completion: nil)
        }
    }
    

    动物采集视图单元格

    class AnimalCollectionViewCell: UICollectionViewCell {
    
        @IBOutlet weak var animalLabel: UILabel!
        @IBOutlet weak var counterLabel: UILabel!
    
        var animal: AnimalModel! {
            didSet {
                self.updateUI()
            }
        }
    
        func updateUI() {
            animalLabel.text = animal.name
            counterLabel.text = "\(animal.amountCounter)"
            self.backgroundColor = animal.color
        }
    
    }
    

    数据

    struct AnimalData {
        static func getAllAnimals() -> [AnimalModel] {
            return [
                AnimalModel(name: "Cats", amountCounter: 0, color: UIColor.red),
                AnimalModel(name: "Dogs", amountCounter: 0, color: UIColor.blue),
                AnimalModel(name: "Fish", amountCounter: 0, color: UIColor.green),
                AnimalModel(name: "Goats", amountCounter: 0, color: UIColor.yellow),
                AnimalModel(name: "Lizards", amountCounter: 0, color: UIColor.cyan),
                AnimalModel(name: "Birds", amountCounter: 0, color: UIColor.purple)
            ]
        }
    }
    

    代表

    protocol DataDelegate {
        func updatedData(for animalObject: AnimalModel, at: IndexPath)
        func zeroOut(for animalObject: AnimalModel, at: [IndexPath])
    }
    

    下面是正在发生的事情的屏幕截图。看看狗是如何被添加为另一个值为23的单元格的?应该发生的是,第二个blue Dogs单元格上的0应更改为23。我不理解更新数据源和重新加载正确的单元格??

    Wrong functionality

    如何简单地将滑块数据传回最初点击的单元格?

    非常感谢您的帮助

    2 回复  |  直到 6 年前
        1
  •  2
  •   Paulw11    6 年前

    您对您的代表团有正确的想法,但您需要能够提供 上下文 返回给您的代表;ie.更新了什么动物?要做到这一点 MainVC 需要保留正在更新的项目的属性,或者需要将此信息提供给 ChildVC 以便将信息提供给 MainVC公司 。我将使用后一种方法。

    协议

    protocol DataDelegate {
        func updatedData(for animalObject: AnimalModel, at: IndexPath)
        func clearAll()
    }
    

    MainVC公司

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "AnimalSegue" {
    
            let childVC = segue.destination as! ChildVC
            childVC.delegate = self
    
            if let indexPath = self.mainCV.indexPath(for: sender as! AnimalCollectionViewCell) {
                let animalData = self.allAnimals[indexPath.item]
                childVC.animal = animalData
                childVC.indexPath = indexPath
            }
    
        }
    }
    
    extension ViewController: DataDelegate {
        func updatedData(for animalObject: AnimalModel, at indexPath: IndexPath ) {
            self.allAnimals[indexPath.item] = animalObject            
            self.mainCV.reloadItems(at: [indexPath])
        }
    
        func clearAll() {
           for index in 0..<self.allAnimals.count {
              self.allAnimals[index].count =0
           }
           self.mainCV.reloadData()
    }
    

    儿童VC

    class ChildVC: UIViewController {
    
    
        @IBOutlet weak var animalTitleLabel: UILabel!
        @IBOutlet weak var labelCounter: UILabel!
        @IBOutlet weak var sliderLabel: UISlider!
    
        var delegate: DataDelegate?  
        var animal: AnimalModel? 
        var indexPath: IndexPath?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            animalTitleLabel.text = animal?.name
            animalTitleLabel.textColor = animal?.color ?? .white
            sliderLabel.value = animal?.count ?? 0
            self.labelCounter.text = "\(Int(sliderLabel.value))"
    
        }
    
        @IBAction func closeButtonPressed(_ sender: UIButton) {
            if let delegate = self.delegate, 
               let indexPath = self.indexPath,
               let animal = self.animal {
                delegate.updatedData(for: animal, at: indexPath)
            }
            self.dismiss(animated: true, completion: nil)
        }
    
    
        @IBAction func sliderChanged(_ sender: UISlider) {
            let newValue = Int(sender.value)
            labelCounter.text = "\(newValue)"
            self.animal.count = newValue
        }
    
        @IBAction func clearAllBtnPressed(_ sender: UIButton) {
            delegate.clearAll()
        }
    
    }
    

    已更新

    我已经更新了我的答案,以展示如何实现全部清除。在这种情况下,没有理由 儿童VC 更新数据模型;它只需调用委托方法即可让 MainVC公司 知道它应该更新模型并刷新集合视图。

    我认为这暗示了 儿童VC “全部清除”按钮的位置错误;如果代码感觉有点笨拙,那么用户体验也可能有点笨拙。“全部清除”按钮应位于 MainVC公司 -动物特定视图上的按钮影响其他动物是没有意义的。它也不是“可发现的”;直到我选择了一种动物,我才知道什么是清除所有。我意识到这只是一个“学习应用程序”,但用户体验是iOS应用程序开发的重要组成部分,因此考虑它永远都不为时尚早;正如您在这里看到的,它还可能影响您设计代码的方式。

        2
  •  0
  •   Vollan    6 年前

    这是一个非常不完整的显示,但我相信这个解决方案是您正在寻找的

    class mainVC {
    
        var counters: [Int] = [0,0,0,0,0]
    
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(forIndexPath: indexPath) as CustomCell
            cell.counterLabel = counters[indexPath.item]
            return cell
        }
    
        func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
            let childVC =  ChildVC()
            childVC.finishedSelecting = { counter in
                self.counters.insert(counter, at: indexPath.item)
                childVC.dismiss()
                self.theCollectionView.reloadItems(at: [indexPath])
                //Or
                self.theCollectionView.reloadData()
            }
    
             present(childVC, animated: true)
    
        }
    }
    
    class childVC {
    
        var finishedSelecting: ((Int) -> ())?
        var counter = 5
        @objc func finishedButtonPressed() {
            finishedSelecting?(counter)
    
        }
    
        func count() {
            counter+=1
        }
    }