以编程方式在UICollectionView Cell中的UI CollectionView

时间:2018-01-02 11:12:04

标签: ios swift uicollectionview uicollectionviewcell uicollectionviewflowlayout

您好我正在尝试使用UICollectionView制作像facebook这样的主页Feed但是在每个单元格中我想要放置另一个具有3个单元格的collectionView。

you can clone the project here

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

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

但删除该行会给我带来此错误

  

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

因为我的细胞有动态高度 这是一个例子

example

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

1 个答案:

答案 0 :(得分:1)

您的第一个问题将通过在OuterCell中为innerCollectionView设置minimumInteritemSpacing来解决。所以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
}

如果您设法正确设置了所有设置,则应在列表中向上和向下滚动时跟踪位置。