停止单个UICollectionView单元格向屏幕中心流动

12
我试图理解为什么集合视图仅将集合中的最后一个单元格居中对齐。
我创建了一个基于流布局的简单集合视图。 我正在使用自动布局标志-我不确定是否会导致此问题。

每当我从集合视图中删除一个单元格时,前几个似乎运作良好并向左滚动。 但是,当我删除倒数第二个时,最后一个单元格突然从左对齐变为中心对齐。 有人有解释吗? 看起来很奇怪。

如何使所有单元格都向左滚动并保持左对齐。

编辑:这是视图层次结构调试:

http://imgur.com/a/NxidO

这是视图行为

Collectionview centring

我制作了一个演示它的简单github:https://github.com/grantkemp/CollectionViewIssue

这是代码:

        var dataforCV = ["short","longer phrase", "Super long Phrase"]

override func viewDidLoad() {
        super.viewDidLoad()
        demoCollectionView.reloadData()
    let layout = UICollectionViewFlowLayout()

    // Bug Description  - > UICollectionViewFlowLayoutAutomaticSize will center Align the layout if it has only a single cell - but it will left align the content if there is more than one cell.

    // I would expect this behaviour to be consistently left aligning the content.

    //How to repeat: If you comment out UICollection​View​Flow​Layout​Automatic​Size then the collection view will show 3 cells being left aligned and it will continue to left align all the content no matter how many cells you remove.

    // But: if you leave turn UICollection​View​Flow​Layout​Automatic​Size on - then it will intially show 3 cells being left aligned, and then as you click to remove each cell they will stay left aligned until the last single cell will suddenly center align in the collection view

    //  see here for the screen recording:https://istack.dev59.com/bledY.gif
    //  see here for the view hierachy debuggins screen: http://imgur.com/a/NxidO

    layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize


    // <-- End Bug Description
    demoCollectionView.collectionViewLayout = layout
}

    //MARk: CollectionView

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? collectionCell
        cell?.text.text  = dataforCV[indexPath.row]

        return cell!

    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dataforCV.count
    }
    //Remove the item from the array if selected
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        dataforCV.remove(at: indexPath.row)
        demoCollectionView.deleteItems(at: [indexPath])
    }
5个回答

10

我使用以下两个步骤成功解决了这个问题:

  1. 向苹果提交了一个bug,关于在使用UICollectionViewFlowLayoutAutomaticSize时注意到的单元格行为变化的奇怪行为。
  2. 通过创建一个修改后的CustomViewFlowLayout(无法找到原来的 SO/github 问题,如果找到了,我会添加它),我完成了一个解决方法。然后我添加了UICollectionViewFlowLayoutAutomaticSize 设定 - 它非常完美地工作了。

示例代码:

class MyLeftCustomFlowLayout:UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        let attributes = super.layoutAttributesForElements(in: rect)

        var leftMargin = sectionInset.left
        var maxY: CGFloat = 2.0

        let horizontalSpacing:CGFloat = 5

        attributes?.forEach { layoutAttribute in
            if layoutAttribute.frame.origin.y >= maxY
                || layoutAttribute.frame.origin.x == sectionInset.left {
                leftMargin = sectionInset.left
            }

            if layoutAttribute.frame.origin.x == sectionInset.left {
                leftMargin = sectionInset.left
            }
            else {
                layoutAttribute.frame.origin.x = leftMargin
            }

            leftMargin += layoutAttribute.frame.width + horizontalSpacing
            maxY = max(layoutAttribute.frame.maxY, maxY)
        }

        return attributes
    }

在 ViewController 中,您需要将流式布局添加到集合视图中才能使其工作:

let layout = MyLeftCustomFlowLayout() 
layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
myCollectionViewReference.collectionViewLayout = layout

我认为集合视图的实现肯定可以简化,但我会进一步研究它,因为我可以看到它的强大之处。


如果你想支持低于iOS 10.0的版本,你也可以使用layout.estimatedItemSize = CGSize(width: 1, height: 1) - mn1

5

在Swift 5中,可以使用UICollectionViewFlowLayout将单元格左对齐,如下所示:

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
self.collectionView.collectionViewLayout = layout

0

当仅剩最后一个单元格时,请尝试查看调试 -> 捕获视图层次结构(即假设您在模拟器中运行)。 我的猜测:一旦只剩下一个单元格,它就会增大。


我也曾经这样认为 - 但是将单元格的背景颜色涂成红色,你会发现它的大小保持不变。 - UKDataGeek
谢谢@xaphod - 我不知道视图调试 - 太棒了。我已经附上了2个单元格和1个单元格的视图调试,看起来有一个新的约束被添加到中心位置,但我不知道如何解决它。你认为这是一个错误吗?http://imgur.com/a/NxidO - UKDataGeek
如果您使用自动大小,则必须有约束从单元格的每一侧明确地流向另一侧。在您的视图调试截屏中,您没有打开查看约束选项,因此我无法看到它们(这是工具栏中间底部附近带有一条线的按钮)。您是否设置了用于不可满足约束的符号断点? - xaphod
嗨 - 我为约束添加了一个符号断点,但似乎没有触发。我也看不到任何自动大小调整的约束。- 我认为这一定是一个错误。还有其他想法吗? - UKDataGeek
感谢 @xaphod 在调试方面的帮助 - 我认为我在上面找到了与创建自己的自定义流程布局相关的答案 - 而且我相当确定我们有一个 bug。 - UKDataGeek
显示剩余3条评论

0

我从这里得到了这个。对我有效,将估计大小设置为无

enter image description here


0

如果与普通的 UICollectionViewFlowLayout 唯一的要求差异是确保第一项始终左对齐,那么只需执行此操作即可:

class MyCustomFlowLayout: UICollectionViewFlowLayout {

   override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        let attributes = super.layoutAttributesForElements(in: rect)

        attributes?.first?.frame.origin.x = sectionInset.left

        return attributes
    }
}

这样做的缺点是它只适用于第一节的第一项。或者,我们可以使用索引路径,该路径方便地与元素属性一起使用:
class MyCustomFlowLayout: UICollectionViewFlowLayout {

   override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        let attributes = super.layoutAttributesForElements(in: rect)

        attributes?.forEach { (elementAttributes) in
            if elementAttributes.indexPath.item == 0 {
                elementAttributes.frame.origin.x = sectionInset.left
            }
        }

        return attributes
    }
}

还可以通过检查(在上面的示例中)elementAttributes.representedElementCategory来仅针对单元格进行定位,此处有文档记录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接