swift 如何用包含相同项目但不同布局的部分替换具有一种布局的部分?

baubqpgj  于 2023-06-21  发布在  Swift
关注(0)|答案(1)|浏览(101)

我在这里创建了一个演示项目来展示我的问题。我使用UiCollectionViewUICollectionViewCompositionalLayoutDiffiableDatasource。我一共有4节,简单命名为Section1Section2&Section3Section4。当视图加载时,我只显示前3个部分,而不显示第4部分。我想要的是,当我点击第1节中的任何项目时,我只想将其布局更改为列表类型。因此,我决定创建另一个第4节,我认为如果我点击第1节项目,我将删除所有项目,只添加第4节,它也显示了与第1节相同的项目,但在列表中。我是这么做的。我将张贴整个代码,因为它不是那么多,将更容易理解我是如何创建部分和添加数据到他们:

class ViewController: UIViewController {
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    enum Section: String, CaseIterable {
        case section1 = "Squares"
        case section2 = "Big Rectangle"
        case section3 = "Rectangles"
        case section4 = "List"
    }
    
    enum SectionItem: Hashable {
        case itemType1(Item1)
        case itemType2
        case itemType3(Item2)
    }
    
    private var dataSource: UICollectionViewDiffableDataSource<Section, SectionItem>!
    
    var itemType1Array = [Item1(text: "1"), Item1(text: "2"), Item1(text: "3"), Item1(text: "4"), Item1(text: "5")]
    var itemType2Array = [Item2(text: "6"), Item2(text: "7"), Item2(text: "8")]
    
    var isShowingList = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        configureCollectionView()
        configureDatasource()
        generateInitialData(animated: true)
    }
    
    // MARK: - Setup CollectionView
    private func configureCollectionView() {
        collectionView.register(SimpleCollectionViewCell.self, forCellWithReuseIdentifier: SimpleCollectionViewCell.reuseIdentifer)
        collectionView.collectionViewLayout = generateLayout()
        collectionView.delegate = self
    }

    private func generateLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout { (sectionIndex: Int,
        layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
            let sectionLayoutKind = Section.allCases[sectionIndex]
            switch sectionLayoutKind {
            case .section1:
                return self.generateSquareLayout()
            case .section2:
                return self.generateBigRectangleLayout()
            case .section3:
                return self.generateRectanglesLayout()
            case .section4:
                return self.generateListLayout()
            }
        }
        
        return layout
    }
    
    private func generateSquareLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)

        let groupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1/3),
            heightDimension: .fractionalWidth(1/3))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = .continuous

        return section
    }
    
    private func generateBigRectangleLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)

        let groupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .fractionalWidth(2/3))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = .continuous

        return section
    }
    
    private func generateRectanglesLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)

        let groupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(2/3),
            heightDimension: .fractionalWidth(1/3))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = .continuous

        return section
    }
    
    private func generateListLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .estimated(44))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 1, leading: 1, bottom: 1, trailing: 1)

        let groupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .estimated(44))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)

        return section
    }
    
    // MARK: - Datasource
    private func configureDatasource() {
        dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView, cellProvider: { [unowned self] collectionView, indexPath, item in
            return self.cell(collectionView: collectionView, indexPath: indexPath, item: item)
        })
    }
    
    // MARK: Cell
    private func cell(collectionView: UICollectionView, indexPath: IndexPath, item: SectionItem) -> UICollectionViewCell {
        switch item {
        case .itemType1(let item1):
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SimpleCollectionViewCell.reuseIdentifer, for: indexPath) as? SimpleCollectionViewCell else { fatalError("Could not create new cell") }
            
            cell.configure(item1.text)

            return cell
            
        case .itemType2:
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SimpleCollectionViewCell.reuseIdentifer, for: indexPath) as? SimpleCollectionViewCell else { fatalError("Could not create new cell") }
            
            cell.configure("Mid")

            return cell
            
        case .itemType3(let item2):
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SimpleCollectionViewCell.reuseIdentifer, for: indexPath) as? SimpleCollectionViewCell else { fatalError("Could not create new cell") }
            
            cell.configure(item2.text)

            return cell
            
        }
    }
    
    private func generateInitialData(animated: Bool) {
        var snapshot = NSDiffableDataSourceSnapshot<Section, SectionItem>()
        
        switch isShowingList {
        case true:
            snapshot.appendSections([.section4])
            snapshot.appendItems(itemType1Array.map { ViewController.SectionItem.itemType1($0) }, toSection: .section4)
            
        case false:
            snapshot.appendSections([.section1, .section2, .section3])
            snapshot.appendItems(itemType1Array.map { ViewController.SectionItem.itemType1($0) }, toSection: .section1)
            snapshot.appendItems([ViewController.SectionItem.itemType2], toSection: .section2)
            snapshot.appendItems(itemType2Array.map { ViewController.SectionItem.itemType3($0) }, toSection: .section3)
        }
        
        dataSource.apply(snapshot, animatingDifferences: animated)
    }
}

// MARK: - UICollectionView Delegate
extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: true)
        
        guard let selectedItem = dataSource.itemIdentifier(for: indexPath) else { return }
        
        switch selectedItem {
        case .itemType1(_):
            var oldSnapshot = dataSource.snapshot()
            switch isShowingList {
            case true:
                oldSnapshot.deleteAllItems()
                oldSnapshot.appendSections([.section1, .section2, .section3])
                oldSnapshot.appendItems(itemType1Array.map { ViewController.SectionItem.itemType1($0) }, toSection: .section1)
                oldSnapshot.appendItems([ViewController.SectionItem.itemType2], toSection: .section2)
                oldSnapshot.appendItems(itemType2Array.map { ViewController.SectionItem.itemType3($0) }, toSection: .section3)
            case false:
                oldSnapshot.deleteAllItems()
                oldSnapshot.appendSections([.section4])
                oldSnapshot.appendItems(itemType1Array.map { ViewController.SectionItem.itemType1($0) }, toSection: .section4)
            }
            isShowingList = !isShowingList
            DispatchQueue.main.async {
                self.dataSource.apply(oldSnapshot, animatingDifferences: true)
            }
        case .itemType2:
            print("section 2")
        case .itemType3(_):
            print("section 3")
        }
    }
}

开始时,它是这样看的:

但是当我点击任何单元格时,我希望它使用我创建的self.generateListLayout()方法显示一个列表,但我只看到这个:

它显示了第1节的布局。在我的主应用程序中,我甚至使用了不同的单元格,并在模型中使用了一些虚拟对象,我使其可清洗,即使这样,单元格也在更新,即使我改变了项目的数量,它也在反映,但布局仍然与第1节相同。我期望使用hashables,它会强制更改布局,但它只更新了数据源,使用了不同的单元格和项目,但布局相同。我想在两个部分中使用相同的数组或项目。有没有其他方法可以达到我的目的?我只想显示10个项目最大在第一节和轻敲任何一个,显示在该阵列中的所有项目,并更改布局列表,还删除其他2节。

dzjeubhm

dzjeubhm1#

所以我只是修改了数据而不是实际的布局。所以我修改了我的方法,告诉collectionView应用新的布局,如下所示:

var oldSnapshot = dataSource.snapshot()
    switch isShowingList {
    case true:
         oldSnapshot.deleteAllItems()
         oldSnapshot.appendSections([.section1, .section2, .section3])
         oldSnapshot.appendItems(itemType1Array.map { ViewController.SectionItem.itemType1($0) }, toSection: .section1)
         oldSnapshot.appendItems([ViewController.SectionItem.itemType2], toSection: .section2)
         oldSnapshot.appendItems(itemType2Array.map { ViewController.SectionItem.itemType3($0) }, toSection: .section3)
    case false:
         oldSnapshot.deleteAllItems()
         oldSnapshot.appendSections([.section4])
         oldSnapshot.appendItems(itemType1Array.map { ViewController.SectionItem.itemType1($0) }, toSection: .section4)
    }
    isShowingList = !isShowingList
         DispatchQueue.main.async {
              self.dataSource.apply(oldSnapshot, animatingDifferences: true)
              if self.isShowingList {
                  let listLayout = self.generateListLayout()
                  collectionView.collectionViewLayout = UICollectionViewCompositionalLayout(section: listLayout)
               } else {
                  let originalLayout = self.generateLayout()
                  collectionView.setCollectionViewLayout(originalLayout, animated: true)
         }
}```

相关问题