2017-04-24 2 views
0

저는 신속한/iOS noobie입니다. 그리고 나는 에베레스트를 첫 번째 과제물로 사용했다고 생각하기 시작했습니다. 어쨌든, 내 애플 리케이션은 스크롤 주간 캘린더보기가 있습니다. 나는 사용자 정의 UICollectionViewLayout을 사용하고 있습니다. 응용 프로그램이 시작되면 모든 것이 잘되는 것처럼 보이며 24 시간 내내 스크롤 할 수 있고 그 날을 통해 오른쪽으로 스크롤 할 수 있습니다 (첫 번째 이미지 참조).UICollectionViewLayout 'freezes'

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; 

보기 계층 디버그에서 : <V3.CDCMonthCell: 0x7feb7410a690; baseClass = UICollectionViewCell; frame = (1201.5 361; 47 50); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x608000035180>>

[UPDATE : (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>

보기 계층 디버그부터 '날짜'셀에 대한 '날짜'셀 터미널에서 인쇄

]

안녕하세요 - 나는 내 코드를 철저히 조사해 보았습니다. 그리고 나서 데이터 소스를 추가 할 때 같은 문제로 끝난 두 개의 튜토리얼을 따랐습니다 (싱글 톤) - 그래서 뜨거운 용의자 (!)가있다. 그러나 나는 단지 그것을 이해할 수 없다. 아래 코드는 튜토리얼 예제를 기반으로하지만 동일한 문제를 보여줍니다.

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

BTW, 앱이 교착 상태가 아니라는 증거가 있어도 컬렉션보기가 업데이트되지 않는 것으로 보이는 경우 백그라운드 스레드의 우발적 인 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