Collection View

16년도 WWDC의 UICollectionView 섹션을 다시 보고, CollectionView와 관련된 정보들을 아카이브 해야겠다고 생각해서 시작하는 포스팅입니다.

develpoer.apple.com :: Official Doc

WWDC 2016

WWDC 2016 :: iOS10 CollectionView New Features

Life Cycle of a Cell

Self-Sizing Cells API

Interactive Reordering

override func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    dataSource.moveDataFrom(sourceIndexPath, toIndexPath: destinationIndexPath)
}

Related Snippets

offset, inset, frame, bounds

// print 찍어보면서 테스트 하기
scrollView.contentOffset.y: -64.0
scrollView.contentInset.top: 64.0
scrollView.bounds.origin.y: -64.0
scrollView.frame.origin.y: 0.0

Pinning Header

Editing Mode

override func setEditing(_ editing: Bool, animated: Bool) {
	super.setEditing(editing, animated: animated)
	addButton.isEnabled = !editing
	collectionView?.allowsMultipleSelection = editing
	if !editing {
		navigationController?.isToolbarHidden = true
	}
	guard let indexes = collectionView?.indexPathsForVisibleItems else {
		return
	}
	for index in indexes {
		let cell = collectionView?.cellForItem(at: index) as! CollectionViewCell
		cell.isEditing = editing
	}
}

Custom FlowLayout

override func prepare() {
	super.prepare() 
	if isSetup == false {
	  setupCollectionView()
	  isSetup = true
	}
}
  
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

    let attributes = super.layoutAttributesForElements(in: rect)
    var attributesCopy = [UICollectionViewLayoutAttributes]()
    
    for itemAttributes in attributes! {
      let itemAttributesCopy = itemAttributes.copy() as! UICollectionViewLayoutAttributes
      changeLayoutAttributes(itemAttributesCopy)
      attributesCopy.append(itemAttributesCopy)
    }
    
    return attributesCopy
}
  
override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
	return true
}

Target ContentOffset

override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    
    let layoutAttributes = self.layoutAttributesForElements(in: collectionView!.bounds)
 
    let center = collectionView!.bounds.size.height / 2
   
     // proposedContentOffset.y 일 때의 Center
    let proposedContentOffsetCenterOrigin = proposedContentOffset.y + center
    
    // 가장 가까운 item과의 거리
    let closest = layoutAttributes!.sorted { abs($0.center.y - proposedContentOffsetCenterOrigin) < abs($1.center.y - proposedContentOffsetCenterOrigin) }.first ?? UICollectionViewLayoutAttributes()
  
    let targetContentOffset = CGPoint(x: proposedContentOffset.x, y: floor(closest.center.y - center))
    return targetContentOffset
}

Stretching Header

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let layoutAttributes = super.layoutAttributesForElements(in: rect)! as [UICollectionViewLayoutAttributes]
    
    let offset = collectionView!.contentOffset
    if (offset.y < 0) {
      let deltaY = fabs(offset.y)
      for attributes in layoutAttributes {
        if let elementKind = attributes.representedElementKind {
          if elementKind == UICollectionElementKindSectionHeader {
            var frame = attributes.frame
            frame.size.height = max(0, headerReferenceSize.height + deltaY)
            print("frame.origin.y: \(frame.origin.y)")
            print("frame.minY: \(frame.minY)")
            print("deltaY: \(deltaY)")
            print("frame.minY - deltaY: \(frame.minY - deltaY)")
            frame.origin.y = frame.minY - deltaY
            print("frame.origin.y: \(frame.origin.y)")
            attributes.frame = frame
          }
        }
      }
    }
    
    return layoutAttributes
}