我有两个 ViewController
: MainVC
, 和 ChildVC
. MainVC
包括 CollectionView
与 5 cell
.每一个 cell
转至 ChildVC
.在此ChildVC
,您可以选择不同的项目来增加(或减少)ChildVC
上的计数器(计数器只显示“## selected”。)
基本上,我只想要 ChildVC
上的计数器数据被传递回相应 MainVC
的标签上被窃听的单元格。例如:如果用户点击 MainVC
上的第二个单元格,选择 ChildVC
上的 13 个项目,然后返回到 MainVC
,第二个单元格的标签中会有一个“13”。然后,如果用户点击第一个单元格,则在 ChildVC
上选择 5 个项目。 ,然后返回到 MainVC
,第一个单元格上的标签中将有一个“5”,而第二个单元格上的标签中将有一个“13”。
我的进度:
我认为委托(delegate)是满足我要求的合适解决方案,因为委托(delegate)可以轻松地将数据传递给/从 VC 传递。我需要帮助从 ChildVC
传回数据致 CollectionView
细胞。
我的问题:
protocol
中传入和传出。 ? (我不确定是否应该传递 indexPath
,以便数据显示在 MainVC
上的正确单元格上?)MainVC
, 如果从 protocol
接收到的数据ChildVC
发送至CollectionViewCell
?或 MainVC
cellForItemAt
方法? 更新:
我在下面有一些进展。但它没有按预期工作。
在下面的代码中,我创建了 ViewController (MainVC) 和 ChildVC。在子 VC 中,有一个 UISlider 来模拟选定的计数器。我希望将此计数器数据传递回各自的 MainVC CollectionView 单元。现在发生的事情是,一旦我更改 slider 的值,MainVC CollectionView 就会添加一个新单元格! '清除所有动物' btn 需要将所有单元格的 slider 数据“归零”,但我还没有走到那一步。
View Controller (上面我的问题中的 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
}
}
child 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)
]
}
}
委托(delegate)
protocol DataDelegate {
func updatedData(for animalObject: AnimalModel, at: IndexPath)
func zeroOut(for animalObject: AnimalModel, at: [IndexPath])
}
下面是正在发生的事情的屏幕截图。看看 Dogs 如何被添加为另一个值为 23 的单元格?应该发生的是,第二个蓝色 Dogs 单元格上的 0 应该变为 23。我不明白更新数据源并重新加载正确的单元格??
我如何简单地将 slider 数据传回最初点击的单元格?
任何帮助表示赞赏
最佳答案
您对您的委托(delegate)有正确的想法,但您需要能够向您的委托(delegate)提供背景信息; IE。什么动物正在更新?为此,MainVC
需要保留正在更新的项目的属性,或者需要将此信息提供给 ChildVC
以便它可以将信息提供回MainVC
.我将使用后一种方法。
协议(protocol)
protocol DataDelegate {
func updatedData(for animalObject: AnimalModel, at: IndexPath)
func clearAll()
}
主VC
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()
}
child 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()
}
}
更新
我已经更新了我的答案,以展示您如何实现 clear all。在这种情况下,没有理由使用
ChildVC
更新数据模型;它只需要调用一个委托(delegate)方法来让 MainVC
知道它应该更新模型并刷新 Collection View 。我认为这暗示了为什么
ChildVC
是“全部清除”按钮的错误位置;如果代码感觉有点笨拙,那么用户体验也可能有点笨拙。清除所有按钮应该在您的 MainVC
上。 - 动物特定 View 上的按钮影响其他动物是没有意义的。它也不是“可发现的”;直到我选择了一种动物,我才知道全部清除。我意识到这只是一个“学习应用”,但用户体验是 iOS 应用开发的重要组成部分,因此考虑它永远不会太早;如您在此处所见,它还会影响您设计代码的方式。
关于ios - 将数据从子 VC 传递回 Collection View Cell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49828058/