【问题标题】:Get indexPath from UICollectionViewController to UICollectionViewCell subclass从 UICollectionViewController 获取 indexPath 到 UICollectionViewCell 子类
【发布时间】:2019-04-11 03:20:49
【问题描述】:

在我的视图控制器中,我正在加载带有子类的自定义 CollectionViewCell。根据单元格索引路径的位置,我想以不同的方式格式化文本标签。 IE。第一行只有一个文本较大的单元格,而第二行有两个文本较小的单元格。

如何从 UICollectionViewCell 子类中的 UICollectionView 访问索引路径?我尝试了一个委托协议,但这总是返回 nil。

下面的代码,非常感谢!

马库斯

UICollectionViewController:

import UIKit

protocol WorkoutDataViewControllerCVDataSource: AnyObject {

func workoutType(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> WorkoutType
func workoutDistance(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
func workoutDuration(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
func workoutInstantVelocity(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
}

final class WorkoutDataViewControllerCV: UIViewController {

@IBOutlet weak var collectionView: UICollectionView!

weak var dataSource: WorkoutDataViewControllerCVDataSource!

private lazy var velocityFormatter = VelocityFormatter(dataSource: self, delegate: self)
private lazy var averageVelocityFormatter = VelocityFormatter(dataSource: self, delegate: self)

override func viewDidLoad() {
    super.viewDidLoad()
    self.collectionView.register(MeasurementCollectionViewCell.preferredNib, forCellWithReuseIdentifier: MeasurementCollectionViewCell.preferredReuseIdentifier)
}

 }

   // MARK: - Managing UICollectionView

 extension WorkoutDataViewControllerCV: UICollectionViewDataSource {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 4
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Measurement Cell", for: indexPath)
    return cell
     }

    }

   extension WorkoutDataViewControllerCV: UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    sizeForItemAt indexPath: IndexPath) -> CGSize {

    let availableWidth = self.view.frame.width

    switch indexPath.row {
    case 0: return CGSize(width: availableWidth, height: 150)
    case 1: return CGSize(width: availableWidth/2.1, height: 150)
    case 2: return CGSize(width: availableWidth/2.1, height: 150)
    case 3: return CGSize(width: availableWidth, height: 150)
    default:
        return CGSize(width: availableWidth/2.1, height: 150)
    }
}
}

   // MARK: - Managing VelocityFormatter

   extension WorkoutDataViewControllerCV: VelocityFormatterDataSource     {

func duration(for velocityFormatter: VelocityFormatter) -> Double {
    return dataSource.workoutDuration(for: self)
}

func distance(for velocityFormatter: VelocityFormatter) -> Double {
    return dataSource.workoutDistance(for: self)
}

func instantVelocity(for velocityFormatter: VelocityFormatter) -> Double {
    return dataSource.workoutInstantVelocity(for: self)
}
}

UICollectionViewCell.swift

    import UIKit

  final class MeasurementCollectionViewCell: UICollectionViewCell {

@IBOutlet private var measurementPropertyLabel: UILabel!
@IBOutlet private var measurementValueLabel: UILabel!
@IBOutlet private var measurementUnitLabel: UILabel!

static let preferredReuseIdentifier = "Measurement Cell"
static let preferredNib = UINib(nibName: "MeasurementCollectionViewCell", bundle: nil)

override func awakeFromNib() {
    super.awakeFromNib()
    updateMeasurement(property: "Speed", value: "100", unit: "km/h")

    //measurementValueLabel.font = measurementValueLabel.font.monospacedDigitFont
}

func updateMeasurement(property: String, value: String, unit: String?) {
    measurementPropertyLabel.text = property
    measurementValueLabel.text = value
    measurementUnitLabel.text = unit
       }

    }

【问题讨论】:

  • 为什么需要cell类内部的索引路径?决定一个单元格是否应该使用不同格式的逻辑不应该是单元格的决定。这应该是视图控制器的决定。
  • @rmaddy 你是对的......我想我的第一个想法是这个类“控制”单元格的 xib,因为 xib 是一个视图,所以它是正确的方法。但是单元格最终是由视图控制器提供的,所以我将把格式放在那里。谢谢!
  • 格式仍然在单元格中,但视图控制器应该告诉单元格它处于什么状态,以便单元格可以适当地绘制自己。
  • @rmaddy 谢谢!但我有点困惑。你将如何控制布局?在cellforitem中?然后加载不同的xib和类?对不起,我不喜欢这些东西。

标签: ios swift uicollectionviewcell


【解决方案1】:

相当直接的方法是将indexPath 存储到UICollectionViewCell 类的子类中。从cellForRow at: index path 返回时分配它。所以现在子类 collectionviewcell 可以访问它自己的 indexpath

【讨论】:

  • 不要这样做。一个单元格永远不应该知道它的索引路径。插入、删除或重新排序单元格时可能会出错。
  • 您能否解释一下在 1. 插入、2. 删除、3. 重新排序的情况下会出现什么问题。
  • 在执行此类操作后,您为单元格指定的索引路径可能是错误的。这就是单元格没有索引路径的原因。一个单元格不应该因为任何原因而需要知道它的索引路径。
  • 是的,我明白了,万一 OP 在这些情况出现时设法更新indexPath,会不会好吗?
  • 但是为什么呢?为什么要把知识强加到不属于它的地方?您可以通过额外的努力使其工作,但关键是您应该尝试使其工作,因为这是错误的解决方案。
【解决方案2】:

在UICollectionView delegate方法collectionView(_, didSelectItemAt _)中获取cell的实例。

extension WorkoutDataViewControllerCV: UICollectionViewDelegate {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        if let cell = collectionView.cellForItem(at: indexPath) as? MeasurementCollectionViewCell {
            cell.selectedIndexPath(indexPath)
        }
    }
}

indexPath 将作为参数在方法 selectedIndexPath 中从上述方法传递给 MeasurementCollectionViewCell。

class MeasurementCollectionViewCell: UICollectionViewCell {

    ......
    func selectedIndexPath(_ indexPath: IndexPath) {

        //Do your business here.
    }
}

【讨论】:

    【解决方案3】:

    您可以使用响应者链来获取单元格的集合视图,您可以使用该视图获取索引路径。只需将这些扩展名添加到一个名为 UICollectionViewCell+IndexPath.swift 的新文件中即可。

    extension UIResponder {
        func next<T: UIResponder>(_ type: T.Type) -> T? {
            return next as? T ?? next?.next(type)
        }
    }
    
    extension UICollectionViewCell {
        var indexPath: IndexPath? {
            return next(UICollectionView.self)?.indexPath(for: self)
        }
    }
    

    现在在您的单元格中,您可以使用self.indexPath

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-29
      • 1970-01-01
      • 2014-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多