具有多个CollectionViewLayout的单个CollectionView。为什么布局混乱?

时间:2018-11-13 05:28:55

标签: ios swift uicollectionview uicollectionviewlayout

我有一个UICollectionView,我想动态地应用两个不同的布局。

  1. UICollectionViewFlowLayout:具有相同大小的单元格和圆形图像的布局。

    var flowLayout: UICollectionViewFlowLayout {
        let flowLayout = UICollectionViewFlowLayout()
    
        flowLayout.itemSize = CGSize(width: UIScreen.main.bounds.width/3, height: 140)
        flowLayout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0)
        flowLayout.scrollDirection = UICollectionViewScrollDirection.vertical
        flowLayout.minimumInteritemSpacing = 0.0
    
        return flowLayout
    }
    
  2. Pintrest Layouthttps://www.raywenderlich.com/392-uicollectionview-custom-layout-tutorial-pinterest

例如:当用户单击“配置文件”按钮时,将显示FlowLayout并以圆形显示单元格。当用户单击“图片”按钮时,将应用最细布局,单元格将以具有动态高度的矩形形状显示。

enter image description here

最初,CollectionView具有1.flowLayout,它看起来很完美。但是,当我单击“图片”按钮时,Pintrest布局与先前的布局混淆了,如上图所示。

以下是更改布局的代码。

if isGrid {
    let horizontal = flowLayout
    recentCollectionView.setCollectionViewLayout(horizontal, animated: true)
    recentCollectionView.reloadData()
}
else {
    let horizontal = PinterestLayout()
    horizontal.delegate = self
    recentCollectionView.setCollectionViewLayout(horizontal, animated: true)
    recentCollectionView.reloadData()
}

ViewHiarchy:

我有一个包含标题和一个底部单元格的主Collection-view.cell包含我要对其应用多个布局的其他Collection-view。每个布局都有两个不同的单元格。我希望底部单元格的大小等于content集合视图的内容大小,以便用户可以垂直滚动整个主集合视图。

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        var cell : UICollectionViewCell!

        switch isGrid {
        case true:
            cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchProfileCell", for: indexPath)
            if let annotateCell = cell as? SearchProfileCell {
                annotateCell.photo = photos[indexPath.item]
            }
        case false:
             cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AnnotatedPhotoCell", for: indexPath)

            if let annotateCell = cell as? AnnotatedPhotoCell {
                annotateCell.cellwidth = collectionView.contentSize.width/3
                annotateCell.photo = photos[indexPath.item]

            }
        }

        cell.contentView.layer.cornerRadius = 0
        return cell
    }

个人资料和图片按钮操作的代码。

@IBAction func pictureClick(sender:UIButton) {
        isGrid = false
        self.searchCollectionView.reloadData()
    }

    @IBAction func profilClick(sender:UIButton) {
        isGrid = true
        self.searchCollectionView.reloadData()
    }

2 个答案:

答案 0 :(得分:2)

我认为问题不在布局内部,而可能在cellForItemAt内部。如果两种布局都使用不同的单元格,则不要在cellForItemAt方法中比较布尔值。您应该比较布局类的类型 像下面的代码:

 func  collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if collectionView.collectionViewLayout.isKind(of: PinterestLayout.self) {
           // return cell for PinterestLayout 
             guard let annotateCell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchProfileCell", for: indexPath) as? SearchProfileCell else {
              fatalError("SearchProfileCell Not Found")
            }
            annotateCell.photo = photos[indexPath.item]
            return annotateCell
        } else {
         // return cell for flowLayout 
              guard let annotateCell = collectionView.dequeueReusableCell(withReuseIdentifier: "AnnotatedPhotoCell", for: indexPath) as? AnnotatedPhotoCell else {
                fatalError("AnnotatedPhotoCell Not Found")
             }
             annotateCell.cellwidth = collectionView.contentSize.width/3
             annotateCell.photo = photos[indexPath.item]
             return annotateCell
        }
 }

还需要更新布局更改操作方法,例如:

     @IBAction func pictureClick(sender:UIButton) {
               isGrid = false

        self.collectionView?.collectionViewLayout.invalidateLayout()  
       self.collectionView?.setCollectionViewLayout(PinterestLayout(), 
             animated: false, completion: { [weak self] (complite) in
                    guard let strongSelf = self else {
                        return
                    }
                    strongSelf.searchCollectionView?.reloadData()
                })
       }

      @IBAction func profilClick(sender:UIButton) {
          isGrid = true
          self.collectionView?.collectionViewLayout.invalidateLayout()              
       self.collectionView?.setCollectionViewLayout(flowLayout, 
             animated: false, completion: { [weak self] (complite) in
                    guard let strongSelf = self else {
                        return
                    }
                    strongSelf.searchCollectionView?.reloadData()
                })
     }

答案 1 :(得分:1)

即使使用pintrestLayout可以获得相同的结果,为什么还要使用两种不同的布局。 https://www.raywenderlich.com/392-uicollectionview-custom-layout-tutorial-pinterest

仔细检查pintrestLayout,它具有动态高度的代表。

 let photoHeight = delegate.collectionView(collectionView, heightForPhotoAtIndexPath: indexPath)

如果您在此处返回静态高度,则您的pintrest布局将成为GridLayout(您的第一个布局)。

如果希望将pintrest布局用作这两种布局,则需要在pintrest布局中声明相同的布尔值(isGrid)。并使用此布尔值返回UICollectionViewLayoutAttributes

更重要的raywenderlich pintrest布局使用缓存来存储布局属性。您必须在应用其他布局之前删除缓存对象。

在本教程中,检查栅格,列表和线性布局的布局。 https://benoitpasquier.com/optimise-uicollectionview-swift/

布局所需的内容。

 var isGrid : Bool = true {
        didSet {
            if isGrid != oldValue {
                cache.removeAll()
                self.invalidateLayout()
            }
        }
    }