首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UICollectionViewLayout‘冻结’

UICollectionViewLayout‘冻结’
EN

Stack Overflow用户
提问于 2017-04-24 19:58:48
回答 1查看 1.3K关注 0票数 1

我是一个快速/iOS noobie,我开始认为我已经把珠穆朗玛峰作为我的第一个任务。无论如何,我的应用程序有一个基于周滚动的日历视图。我正在使用自定义的UICollectionViewLayout。当应用程序启动时,一切看起来都很好,我可以在24小时内向下滚动,直到白天(见第一张图片)。

当用户到达预定义的单元格数(天数)结束时,会向数据源添加更多的单元格。我可以愉快地继续滚动,代码可以根据需要添加更多的单元格。

问题是:

当我停止滚动在任何额外的数据(天)被添加到数据源后的日子,然后重新开始滚动布局冻结在一个单一的块,只是浮动(见第二个图像)。

正确的单元格放置(钉扎)到视图顶部不再工作(因为它只是上述冻结的单元格块),并且不显示新的单元格。

奇怪的是,在布局冻结之后,终端继续从UICollectionViewLayout注销调试,将单元格放置在正确的位置,尽管UICollectionViewController似乎已经停止监听了吗?

打印在“日期”单元格的终端中:Cell attributes: <UICollectionViewLayoutAttributes: 0x6080003edf00> index path: (<NSIndexPath: 0x60800003a760> {length = 2, path = 2 - 0}); frame = (1033 235; 47 50); zIndex = 1024;

从视图层次结构调试:(UICollectionView): <UICollectionView: 0x7feb7302d000; frame = (0 0; 667 375); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x600000051490>; layer = <CALayer: 0x6000000329a0>; contentOffset: {1033, 235}; contentSize: {2651, 910}> collection view layout: <V3.CDCLayout: 0x7feb7140f1a0>

从“日期”单元格的视图层次结构调试:<V3.CDCMonthCell: 0x7feb7410a690; baseClass = UICollectionViewCell; frame = (1201.5 361; 47 50); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x608000035180>>

更新

嗨,罗伯-我试着把我的代码拿回来,然后又跟着几个教程,当我添加我的数据源(单例)时,这些教程都以相同的问题结束--所以有一个热门的嫌疑人(!)但我就是搞不懂。下面的代码基于一个教程示例,但显示了相同的问题。

CollectionViewController:

代码语言:javascript
复制
private let reuseIdentifier = "cCell"

class CustomCollectionViewController: UICollectionViewController {

    let localItems = Items.items.getItems()


    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 6  }


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return Items.items.getItemCount()
    }

    override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {

        if (Items.items.getItemCount() - indexPath.row ) == 2 {
            Items.items.addItems()
            collectionView.reloadData()
            collectionView.collectionViewLayout.invalidateLayout()
        }
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> CustomCollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CustomCollectionViewCell

        cell.textLabel.text = "SEC=\(indexPath.section),IXDI=\(indexPath.item)"

        return cell
    }
}

布局:

代码语言:javascript
复制
class CustomCollectionViewLayout: UICollectionViewLayout {

    let CELL_HEIGHT = 145.0
    let CELL_WIDTH = 145.0
    let STATUS_BAR = UIApplication.shared.statusBarFrame.height
    var cellAttrsDictionary = Dictionary<IndexPath, UICollectionViewLayoutAttributes>()
    var contentSize = CGSize.zero

    override var collectionViewContentSize : CGSize {
        return contentSize
    }

    override func invalidateLayout() {
        super.invalidateLayout()
        cellAttrsDictionary.removeAll()
    }

    override func prepare() {

        if (collectionView?.numberOfSections)! > 0 {
            for section in 0...collectionView!.numberOfSections-1 {

               if (collectionView?.numberOfItems(inSection: section))! > 0 {
                    for item in 0...collectionView!.numberOfItems(inSection: section)-1 {

                        let cellIndex = IndexPath(item: item, section: section)
                        let xPos = Double(item) * CELL_WIDTH
                        let yPos = Double(section) * CELL_HEIGHT

                        let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
                        cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)

                        if section == 0 && item == 0 {
                            cellAttributes.zIndex = 4
                        } else if section == 0 {
                            cellAttributes.zIndex = 3
                        } else if item == 0 {
                            cellAttributes.zIndex = 2
                        } else {
                            cellAttributes.zIndex = 1
                        }

                        cellAttrsDictionary[cellIndex] = cellAttributes
                    }
                }
            }
        }

        let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
        let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
        self.contentSize = CGSize(width: contentWidth, height: contentHeight)
    }

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

        for cellAttributes in cellAttrsDictionary.values {
            if rect.intersects(cellAttributes.frame) {
                attributesInRect.append(cellAttributes)
            }
        }
        return attributesInRect
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return cellAttrsDictionary[indexPath]!
    }

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
}

项目/数据-源/单例:

代码语言:javascript
复制
class Items {

    static var items = Items() // Singleton

    var classItems = [Int]()

    init() {
        addItems()
    }

    func getItemCount() -> Int {
        return classItems.count
    }

    func getItems() -> [Int] {
        return classItems
    }

    func addItems() {
        for i in 1 ... 7 {
            classItems.append(i)
        }
    }

}
EN

回答 1

Stack Overflow用户

发布于 2017-05-09 02:11:46

在我的测试中,重新加载willDisplay中的数据源似乎是问题的根源。通过DispatchQueue.main.async { ... },问题似乎消失了。

代码语言:javascript
复制
private var lastReloadedRow = 0

override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if (Items.items.getItemCount() - indexPath.row) == 2 && lastReloadedRow < indexPath.row {
        lastReloadedRow = indexPath.row
        DispatchQueue.main.async {
            Items.items.addItems()
            collectionView.reloadData()
        }
    }
}

注意,我添加了一个state属性来跟踪我们是否已经加载了,因为按照它的方式,它是多次不必要地重新加载的。

为了完整起见,这里是我对您的自定义布局的完整实现。我做了几件无关的事:

因此:

代码语言:javascript
复制
class CustomCollectionViewLayout: UICollectionViewLayout {

    let CELL_HEIGHT = 145.0
    let CELL_WIDTH = 145.0
    let STATUS_BAR = UIApplication.shared.statusBarFrame.height
    var cellAttrsDictionary = Dictionary<IndexPath, UICollectionViewLayoutAttributes>()
    var contentSize = CGSize.zero

    override var collectionViewContentSize : CGSize {
        return contentSize
    }

    override func invalidateLayout() {
        super.invalidateLayout()
        cellAttrsDictionary.removeAll()
    }

    override func prepare() {
        if collectionView!.numberOfSections > 0 {
            for section in 0 ..< collectionView!.numberOfSections {
                if collectionView!.numberOfItems(inSection: section) > 0 {
                    for item in 0 ..< collectionView!.numberOfItems(inSection: section) {
                        let cellIndex = IndexPath(item: item, section: section)
                        let xPos = Double(item) * CELL_WIDTH
                        let yPos = Double(section) * CELL_HEIGHT

                        let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
                        cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)

                        cellAttrsDictionary[cellIndex] = cellAttributes
                    }
                }
            }
        }

        let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
        let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
        contentSize = CGSize(width: contentWidth, height: contentHeight)
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return cellAttrsDictionary.values.filter { $0.frame.intersects(rect) }
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return cellAttrsDictionary[indexPath]!
    }

    // override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    //     return true
    // }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43596708

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档