1

嗨,我正在尝试使用 UICollectionView 制作像 facebook 这样的家庭提要,但是在每个单元格中,我想放置另一个具有 3 个单元格的 collectionView。

您可以在此处克隆项目

我有两个错误,第一个是当我在内部集合上滚动时查看反弹不会将单元格带回中心。当我创建集合视图时,我启用了分页并将 minimumLineSpacing 设置为 0,我不明白为什么会这样。当我尝试调试时,我注意到当我删除此行时此错误停止

layout.estimatedItemSize = CGSize(width: cv.frame.width, height: 1)

但是删除那条线会给我带来这个错误

未定义 UICollectionViewFlowLayout 的行为,因为:项目高度必须小于 UICollectionView 的高度减去部分插入顶部和底部值,减去内容插入顶部和底部值

因为我的单元格有一个动态高度这里是一个例子

例子

我的第二个问题是每个内部单元格上的文本都显示好文本我必须滚动到内部集合视图的最后一个单元格才能看到这里显示的好文本是一个例子 例子

4

1 回答 1

1

您的第一个问题将通过minimumInteritemSpacing在 OuterCell 中设置 innerCollectionView 来解决。所以 innerCollectionView 的定义变成了这样:

let innerCollectionView : UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    layout.minimumLineSpacing = 0
    layout.minimumInteritemSpacing = 0

    let cv = UICollectionView(frame :.zero , collectionViewLayout: layout)
    cv.translatesAutoresizingMaskIntoConstraints = false
    cv.backgroundColor = .orange
    layout.estimatedItemSize =  CGSize(width: cv.frame.width, height: 1)
    cv.isPagingEnabled = true
    cv.showsHorizontalScrollIndicator = false

    return cv

}()

第二个问题通过在 OuterCell 的 post 属性的 didSet 中添加对 reloadData 和 layoutIfNeeded 的调用来解决,如下所示:

var post: Post? {
    didSet {
        if let numLikes = post?.numLikes {
            likesLabel.text = "\(numLikes) Likes"
        }

        if  let numComments = post?.numComments {
            commentsLabel.text = "\(numComments) Comments"
        }
        innerCollectionView.reloadData()
        self.layoutIfNeeded()
    }
}

您所看到的与单元重用有关。如果您滚动到第一项上的黄色边框文本,然后向下滚动,您可以看到这一点。你会看到其他人也在黄色边框的文本上(尽管现在至少有正确的文本)。

编辑

作为奖励,这里是一种记住细胞状态的方法。

首先,您需要跟踪位置何时发生变化,因此在 OuterCell.swft 中添加一个新协议,如下所示:

protocol OuterCellProtocol: class {
    func changed(toPosition position: Int, cell: OutterCell)
}

然后将该协议的委托的实例变量添加到 OuterCell 类,如下所示:

public weak var delegate: OuterCellProtocol?

然后最后您需要添加以下方法,该方法在滚动完成时调用,计算新位置并调用委托方法让它知道。像这样:

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    if let index = self.innerCollectionView.indexPathForItem(at: CGPoint(x: self.innerCollectionView.contentOffset.x + 1, y: self.innerCollectionView.contentOffset.y + 1)) {
        self.delegate?.changed(toPosition: index.row, cell: self)
    }
}

这就是每个单元格检测集合视图单元格何时更改并通知委托人。让我们看看如何使用这些信息。

OutterCellCollectionViewController 将需要跟踪其集合视图中每个单元格的位置,并在它们变得可见时更新它们。

因此,首先使 OutterCellCollectionViewController 符合 OuterCellProtocol,以便在其中一个时通知它

class OutterCellCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, OuterCellProtocol   {

然后添加一个类实例变量以将单元格位置记录到 OuterCellCollectionViewController,如下所示:

var positionForCell: [Int: Int] = [:]

然后添加所需的 OuterCellProtocol 方法来记录单元格位置的变化,如下所示:

func changed(toPosition position: Int, cell: OutterCell) {
    if let index = self.collectionView?.indexPath(for: cell) {
        self.positionForCell[index.row] = position
    }
}

最后更新 cellForItemAt 方法以设置单元格的委托并使用新的单元格位置,如下所示:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OutterCardCell", for: indexPath) as! OutterCell
    cell.post = posts[indexPath.row]

    cell.delegate = self

    let cellPosition = self.positionForCell[indexPath.row] ?? 0
    cell.innerCollectionView.scrollToItem(at: IndexPath(row: cellPosition, section: 0), at: .left, animated: false)
    print (cellPosition)

    return cell
}

如果您设法正确完成所有设置,它应该在您向上和向下滚动列表时跟踪位置。

于 2018-01-02T12:22:33.567 回答