UICollectionViewCells 中的 UIPickerViews 中的 3 个 UILabels 之间不需要的交互

Unwanted interactions between 3 UILabels within UIPickerViews within UICollectionViewCells

使用 UICollectionViewCells 网格中列顶部的选择器独立控制每列的​​内容:

每个选择器应仅更新该列中单元格的值(图像中仅更新第 1 列)。

数据更新的同时,采摘者的标签变得很混乱!

1) 当用户在第 1 列或第 4 列的顶部选择一个新值时 - 例如从男性变为中性。

1a) 列的数据更新 - 为中性 - 但使用的选择器上的标签恢复为之前的值 - 男性。

1b) 同时,未选中的选择器的标签(col. 1 or 4 - NOT 3)更新为选中的选择器中选择的值(未更改未选中列中的值)

在图片中,第 1 列已从阳性更新为中性(Das Kind 为中性;den Ball 为阳性):

2)选值时第3列不同

2a) 数据和选择器标签更新正确(没有恢复到以前的选择器标签值)。

2b) 如果第 1 列和第 4 列有不同的标签——例如第 1 列男性和第 4 列中性,它们交换选择器标签值(它们的数据没有变化)!

我在 item 方法的集合视图单元格中的自定义集合视图单元格中实例化我的选取器。我正在使用 indexPath.item 来区分单元格和选择器 (caseOfPickers) - 至少似乎可以控制数据。

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
    var cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseI4CVCell, for: indexPath) as! CVCell

    switch indexPath.item
    {
        case 0, 2, 3:
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseI4PickerCVCell, for: indexPath) as! PickerCVCell
            cell.caseOfPicker = indexPath.item
            cell.reference = self
            return cell
    ...

那么选择器所在的整个自定义集合视图单元格是:

import UIKit
import CoreData

class PickerCVCell: UICollectionViewCell, UIPickerViewDelegate, UIPickerViewDataSource
{
var reference: EgPickerDelegate?
var caseOfPicker: Int?

private var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>?

@IBOutlet weak var pickerInCVCell: UIPickerView!

override func awakeFromNib()
{
    super.awakeFromNib()
    configureFetchedResultsController()

    pickerInCVCell.delegate = self
    pickerInCVCell.dataSource = self
}

private func configureFetchedResultsController()
{
    ...
}

func numberOfComponents(in pickerView: UIPickerView) -> Int
{ return 1 }

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{ return 4 }

func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView
{
    var pickerLabel: UILabel? = (view as? UILabel)
    let path = NSIndexPath(item: row, section: 0)
    if let gender = fetchedResultsController?.object(at: path as IndexPath) as? Gender
    {
        let text = gender.text ?? "Text not found"
        print("pickerText", text)

        if pickerLabel == nil
        {
            pickerLabel = UILabel()
            pickerLabel?.textColor = UIColor.black
            pickerLabel?.textAlignment = NSTextAlignment.center
            pickerLabel?.font = pickerLabel?.font.with( .traitBold, .traitItalic)
        }
        pickerLabel?.text = text
    }

    return pickerLabel!
}

reference?.myPickerDidSelectRowInCase(selectedRowValue: row, caseOfPicker: caseOfPicker) }

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{ reference?.myPickerDidSelectRowInCase(selectedRowValue: row, caseOfPicker: caseOfPicker) }

func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat
{ return CGFloat(120.0) }
}

回到自定义class控制集合视图,选择器委托方法为:

extension EgEndingsCVTVCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, EgPickerDelegate
{
func myPickerDidSelectRowInCase(selectedRowValue: Int?, caseOfPicker: Int?)
{
    switch caseOfPicker
    {
    case 0:
        col0GenderPredicate = genderPredicator(selectedRowValue: selectedRowValue ?? 0)
    case 2:
        col2GenderPredicate = genderPredicator(selectedRowValue: selectedRowValue ?? 0)
    case 3:
        col3GenderPredicate = genderPredicator(selectedRowValue: selectedRowValue ?? 0)
    default:
        col0GenderPredicate = genderPredicator(selectedRowValue: 0)
    }
loadSavedData()     // load data using new predicates
cView.reloadData()
}

不确定为什么选择器的标签会混淆 - 它们不是作为单独的对象实例化的吗?

出现此问题是因为在选取器委托方法结束时重新加载了整个集合视图。发生这种情况时,UIPickerView 本身会重新加载,并且它们在选择器上的当前显示状态(而不是其他值)会变得混乱。

只更新第 2 行以后的现有集合视图单元格而不重新加载选择器视图,基本上:

let indexPath = IndexPath(item: 4, section: 0)     // item 4 defines the index to column 1 row 2 
let cell = myCollectionView.cellForItem(at: indexPath) as! CollectionViewCell     // use the indexPath to get the existing cell at this position
cell.label.text = theNewText    // and just update this cell's label text.