2017-08-08 2 views
0

私のレイアウトでシェルフのようなモードでデコレーションビューを実装することに固執しています。最初は、スクロール時に新しいdecorationView要素を生成し、それらをキャッシュに追加しません。しかし、最後のセルのindexPathでdecorationViewを生成しようとすると、すぐにアイテムのアプリケーションを削除するときにクラッシュします。私はデコレーションビューのキャッシュを実装して、layoutAttributesForElements(in rect: CGRect)にチェックしてみましたが、アプリが起動するよりも奇妙だと思います。最初に画面に表示されなかったアイテムを削除しようとすると、すぐにアプリケーションがクラッシュします。しかし、最初にそれらの要素のいくつかの要素を削除し、最後から要素を削除し始めたら、すべてうまくいく。 これらのデコレータをレイアウトに追加するにはどうすればよいですか?今の私のコードは以下の行く:1)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

[OK]を、私は2つのことが発見しました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() 
    } 
関連する問題