     }
     
     private func updateAllRowsWidth() {
-        headerInfo?.frame.size.width = collectionViewWidth
+        if headerInfo != nil {
+            headerInfo!.frame.size.width = collectionViewWidth
+            headerInfo!.estimatedHeight = true
+        }
+        
         let rowWidth = collectionViewWidth - (sectionInsets.left + sectionInsets.right)
         
         for row in 0 ..< rowsInfo.count {
             rowsInfo[row].frame.size.width = rowWidth
-        }
-        
-        footerInfo?.frame.size.width = collectionViewWidth
+            rowsInfo[row].estimatedHeight = true
+        }
+        
+        if footerInfo != nil {
+            footerInfo!.frame.size.width = collectionViewWidth
+            footerInfo?.estimatedHeight = true
+        }
     }
     
     private func updateAllRowsOriginY() {

        var info: Any? = nil
        switch elementCategory {
        case .cell(let indexPath):
            let rowInfo = rowsInfo[indexPath.item]
            rowsInfo[indexPath.item] = RowInfo(estimatedHeight: false, frame: CGRect(origin: rowInfo.frame.origin, size: preferredSize))
            info = indexPath
        case .supplementaryView(_, let elementKind):
            if elementKind == UICollectionElementKindSectionHeader {
                headerInfo = RowInfo(estimatedHeight: false, frame: CGRect(origin: headerInfo!.frame.origin, size: preferredSize))
                info = kInvalidateHeaderForPreferredHeight
            }
            else if elementKind == UICollectionElementKindSectionFooter {
                footerInfo = RowInfo(estimatedHeight: false, frame: CGRect(origin: footerInfo!.frame.origin, size: preferredSize))
            }
            
        default: break


//MARK: - Utils
fileprivate struct RowInfo: CustomStringConvertible {
    var estimatedHeight: Bool
    var frame: CGRect
    
    var description: String {
