首页 > 解决方案 > UICollectionViewCells 中的 UIPickerViews 中的 3 个 UILabel 之间不需要的交互

问题描述

使用 UICollectionViewCells 网格中列顶部的选择器来独立控制每列的​​内容: 在此处输入图像描述

每个选择器应仅更新该列中单元格的值(仅更新图像中的第 1 列)。 在此处输入图像描述

在数据更新的同时,拣货员的标签变得非常混乱!

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

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

1b)同时,未选择的选择器的标签(第 1 列或第 4 列 - 非 3)更新为在选择的选择器中选择的值(不更改未选择的列中的值)

在图像中,第 1 列从阳性更新为中性(Das Kind 是中性;den Ball 是阳性): 在此处输入图像描述

2) 选择值时第 3 列不同。

2a) 数据和选择器标签正确更新(不会恢复到之前的选择器标签值)。

2b) 如果第 1 列和第 4 列有不同的标签 - 例如 col 1 Masculine 和 col 4 Neutral 他们交换选择器标签值(不改变他们的数据)! 在此处输入图像描述

我在 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) }
}

回到控制集合视图的自定义类中,选择器委托方法是:

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

不知道为什么选择器的标签会混淆——它们不是被实例化为单个对象吗?

标签: swiftuicollectionviewuipickerview

解决方案


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

要仅从第 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.

推荐阅读