将子VC中的数据传递回Collection View Cell

时间:2018-04-14 04:52:06

标签: ios swift uicollectionview delegates protocols

我有两个ViewControllerMainVCChildVCMainVC包含CollectionViewcell。这些cell中的每一个都转移到ChildVC。在ChildVC上,您可以选择不同的项目来增加(或减少)ChildVC上的计数器(计数器只读取#34; ##选择"。)

基本上,我只希望将ChildVC上的这些计数器数据传回到被点击的相应MainVC单元格的标签上。例如:如果用户点击MainVC上的第二个单元格,则选择ChildVC上的13个项目,然后返回MainVC,将会有一个" 13&#34 ;在第二个单元格的标签上。然后,如果用户点击第一个单元格,则选择ChildVC上的5个项目,然后返回MainVC,将会有一个" 5"在第一个单元格的标签上以及" 13"在第二个细胞上。

我的进步:

我已经决定委托是我的要求的合适解决方案,因为委托可以很容易地将数据传入VC /从VC传递数据。我需要帮助将数据 BACK ChildVC 转发到 CollectionView单元格。

我的问题:

  • 除了选定的计数器计数(Int),还应该在protocol内传递哪些其他信息? (我不确定是否应该传递indexPath,以便数据显示在MainVC上的正确单元格上?)
  • MainVC上,是否应将protocol ChildVC收到的数据发送至CollectionViewCell?还是MainVC cellForItemAt方法?

更新

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

在下面的代码中,我创建了ViewController(MainVC)和ChildVC。在Child VC中,有一个UISlider可以模拟选定的计数器。我希望这些计数器数据传回各自的MainVC CollectionView Cells。现在发生的是当我更改滑块的值时,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
    }
}

ChildVC

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

下面列出了正在发生的事情。看看Dogs如何被添加为另一个值为23的单元格?应该发生的是0应该变为第二个蓝狗Dog上的23。我不明白更新数据源并重新加载正确的单元格

Wrong functionality

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

感谢任何帮助

2 个答案:

答案 0 :(得分:1)

您对自己的代表团有正确的想法,但您需要能够将 context 提供给您的代表;即。什么动物正在更新?要执行此操作,MainVC需要保留正在更新的项的属性,或者需要将此信息提供给ChildVC,以便它可以将信息提供回{{1} }}。我将使用后一种方法。

协定

MainVC

<强> MainVC

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

<强> ChildVC

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

<强>更新

我已经更新了我的答案,以展示如何实现清除所有。在这种情况下,没有理由让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() } } 更新数据模型;它只需要调用一个委托方法让ChildVC知道它应该更新模型并刷新集合视图。

我认为这提示了为什么MainVC对于&#34;清除所有&#34;的错误位置。按钮;如果代码感觉有点笨拙,那么用户体验也可能有点笨拙。清除所有按钮应该在ChildVC上 - 对于动物特定视图上的按钮影响其他动物没有意义。它也不会被发现&#34 ;;在我选择一只动物之前,我都没有发现清楚的一切。我意识到这只是一个学习应用程序&#34;但是用户体验是iOS应用开发的重要组成部分,所以考虑它永远不会太早;它也会影响您设计代码的方式,如您所见。

答案 1 :(得分:0)

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

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