2017-04-24 89 views
0

我是一个SWIFT/iOS noobie,我开始认为我已经把Everest作为我的第一个任务。无论如何,我的应用程序都有一个滚动的基于星期的日历视图。我正在使用自定义UICollectionViewLayout。当应用程序启动时,一切看起来都不错,我可以向下滚动浏览24小时,并浏览日期(请参阅第一张图片)。UICollectionViewLayout'冻结'

Layout on start-up

当用户到达细胞的预定数量的结束(天)多个小区被添加到数据源。我可以愉快地连续向右滚动,代码根据需要添加更多单元格。

问题:

当我停止通过天滚动后的任何额外数据(天)已经被加入到该数据源,和然后重新开始滚动的布局在单个块中冻结,只是漂浮周围(见第二张图片)。细胞

'Frozen' layout

正确位置(钉)到视图顶部不再工作(如细胞的它只是上述冻结块),并显示没有新的细胞。

奇怪的是,在布局冻结后,终端继续从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>>

[UPDATE ]

嗨抢 - 我试图剥离我的代码,然后也跟着几个教程,所有结束时,我添加我的数据源时,同样的问题(单身人士) - 所以有一个热门的嫌疑犯(!),但我无法想象它。下面的代码基于教程示例,但展示了相同的问题。

CollectionViewController:

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 
    } 
} 

布局:

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 
    } 
} 

项目/数据源/单:

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) 
     } 
    } 

} 
+1

这将是很难诊断这种无代码。我建议你创建一个[最小的,完整的,可验证的例子(MCVE)](http://stackoverflow.com/help/mcve)的问题,然后发布该图像和代码为该MCVE。但是在这里我们没有足够的了解哪里出了问题,我们绝对不想看到产生这些图像的所有代码。我们需要使用代码的MCVE。 – Rob

+0

谢谢你看看这个Rob。对MCVE有很好的建议。让我这样做。 – smarts

+0

顺便说一句,如果你的集合视图看起来没有更新,即使你有证据表明应用程序没有死锁,我会留意任何来自后台线程的意外UI更新(或者你手动调度到后台队列或在URLSession完成处理程序中的某个内容,该处理程序在后台队列上运行)。确保在任何后台线程上没有任何'reloadData'或类似的调用。 – Rob

回答

0

在我的测试中,数据源的willDisplay重装似乎成为问题的根源。通过DispatchQueue.main.async { ... }这些问题似乎消失了。

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() 
     } 
    } 
} 

注意,我添加了一个国有资产跟踪我们是否已经加载,因为它的样子,这是不必要的重装多次。


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

这样:

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

协议似乎排除谢谢;但嘿 - 信贷在哪里应有的 - 伟大的工作。在额外的调整上取得好成绩。 – smarts