2017-08-08 55 views
0

我坚持在我的布局中以货架状模式实现装饰视图。起初,我想在滚动时生成新的decorationView元素,并且不要将它们添加到缓存中。但是当我尝试使用最后一个单元格的indexPath生成decorationView时,删除项目app时立即崩溃。比起,我尝试为装饰视图实现一些缓存,在layoutAttributesForElements(in rect: CGRect)中检查它们,但是应用程序开始出现奇怪的想法:如果我尝试删除一开始没有出现在屏幕上的某个项目,应用程序立即崩溃。但是,如果我先删除这些元素的几个元素,然后从最后开始删除元素,一切都会很好。 如何更好地将这些装饰器添加到我的布局中?我现在的代码低于:Swift collectionView添加货架装饰器

class YourFoodFlowLayout: UICollectionViewFlowLayout { 
private enum DecorationViewKind: String { 
    case shelfView = "ShelfView" 
} 

private var cashedDecorationView = [UICollectionViewLayoutAttributes]() 

override init() { 
    super.init() 
    self.register(ShelfCollectionReusableView.self, forDecorationViewOfKind: DecorationViewKind.shelfView.rawValue) 
} 


required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    self.register(ShelfCollectionReusableView.self, forDecorationViewOfKind: DecorationViewKind.shelfView.rawValue) 
} 

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 
    guard let atributes = super.layoutAttributesForElements(in: rect) else { 
     return nil 
    } 
    var mutatingAtributes = atributes 
    //find max Y position of the cells 

    var position = CGRect.zero 
    position.size.width = rect.size.width 
    position.size.height = 16 

    for atribute in mutatingAtributes { 
     atribute.zIndex = 1 
     if atribute.frame.maxY > position.origin.y { 
      position.origin.y = atribute.frame.maxY 
      if rect.intersects(position) { 
       var atribute: UICollectionViewLayoutAttributes? = nil 
       for decorationView in cashedDecorationView { 
        if decorationView.frame == position { 
         atribute = decorationView 
        } 
       } 
       if let atribute = atribute { 
        mutatingAtributes.append(atribute) 
       } else { 
        guard let shelfAtribute = layoutAttributesForDecorationView(ofKind: DecorationViewKind.shelfView.rawValue, at: IndexPath(index: cashedDecorationView.count)) else { 
         continue 
        } 
        shelfAtribute.frame = position 
        cashedDecorationView.append(shelfAtribute) 
        mutatingAtributes.append(shelfAtribute) 
       } 
      } 

     } 
    } 

    return mutatingAtributes 
} 

override func prepare() { 
    super.prepare() 

} 

override var collectionViewContentSize: CGSize { 
    return CGSize(width: super.collectionViewContentSize.width, height: super.collectionViewContentSize.height + 16) 
} 

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 
    return super.layoutAttributesForItem(at: indexPath) 
} 


override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 
    switch elementKind { 
    case DecorationViewKind.shelfView.rawValue: 
     return UICollectionViewLayoutAttributes(forDecorationViewOfKind: elementKind, with: indexPath) 
    default: 
     print("Unexpected decoration layout element kind") 
     return nil 
    } 
} 

}

回答

0

好吧,我发现了两件事情:1)layoutAttributesForElements(in rect: CGRect)滚动时不叫,每次; 2)collectionViewLayout有一些之前使用过的缓存indexPath。即使您尝试重新加载一些数据,您也必须先致电invalidateLayout()重新加载这些indexPath。以下对我有所帮助:

private var cachedDecorationView = [UICollectionViewLayoutAttributes]() 
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 
     //Tip: layoutAtributes with the same indexPath may can not be allowed for reusing 
     guard let atributes = super.layoutAttributesForElements(in: rect) else { 
      return nil 
     } 
     var mutatingAtributes = atributes 

     //find max Y position of the cells 
     var position = CGRect.zero 
     position.size.width = rect.size.width 
     position.size.height = shelfSize 

     for atribute in mutatingAtributes { 
      atribute.zIndex = 1 
      if atribute.frame.maxY > position.origin.y { 
       position.origin.y = atribute.frame.maxY 
       if rect.intersects(position) { 
        let shelf = prerareShelves(for: position) 
        mutatingAtributes.append(shelf) 
       } 

      } 
     } 

     return mutatingAtributes 
    } 

    func prerareShelves(for rect: CGRect) -> UICollectionViewLayoutAttributes { 
     for cache in cachedDecorationView { 
      if cache.frame == rect { 
       return cache 
      } 
     } 
     let indexForNewDecoration = Int(rect.origin.y/itemSize.height + shelfSize) 
     let decoratorView = layoutAttributesForDecorationView(ofKind: DecorationViewKind.shelfView.rawValue, at: IndexPath(item: indexForNewDecoration, section: 0))! 
     decoratorView.frame = rect 
     cachedDecorationView.append(decoratorView) 
     return decoratorView 
    } 
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { 
     return collectionView?.bounds.size != newBounds.size 
    } 

    override func invalidateLayout() { 
     super.invalidateLayout() 
     //delete all cached decoration views before new layout process 
     cachedDecorationView.removeAll() 
    }