在水平集合视图中为部分背景视图设置正确的高度

问题描述 投票:0回答:1

我正在使用以下代码尝试现代集合视图。

此代码中唯一的问题是部分背景高度是从最后一项填充的。如果我保持集合视图滚动到垂直,则可以正常工作。

class SectionDecorationViewController: UIViewController {

    static let sectionBackgroundDecorationElementKind = "section-background-element-kind"

    var currentSnapshot: NSDiffableDataSourceSnapshot<Int, Int>! = nil
    var dataSource: UICollectionViewDiffableDataSource<Int, Int>! = nil
    var collectionView: UICollectionView! = nil
    var currentSelection: Bool = false

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.title = "Section Background Decoration View"
        configureHierarchy()
        configureDataSource()
    }
}

extension SectionDecorationViewController {
    /// - Tag: Background
    func createLayout() -> UICollectionViewLayout {

        let sectionProvider = { [weak self] (sectionIndex: Int,
                                 layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in



            guard let self = self else { return nil }

            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                  heightDimension: .absolute(44))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)

            // Get the number of items in the section
            let itemCount = self.currentSnapshot.numberOfItems(inSection: sectionIndex)

            // Custom group height based on the number of items
            let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                   heightDimension: .absolute(CGFloat(itemCount) * 44))
            let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

            let section = NSCollectionLayoutSection(group: group)
            section.orthogonalScrollingBehavior = .paging
            section.interGroupSpacing = 0 // Remove inter-group spacing
            section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) // Remove content insets

            // Add the background decoration item
            let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background(
                elementKind: SectionDecorationViewController.sectionBackgroundDecorationElementKind)
            section.decorationItems = [sectionBackgroundDecoration]
            return section
        }
        
        let config = UICollectionViewCompositionalLayoutConfiguration()
        config.scrollDirection = .horizontal
        config.interSectionSpacing = 0
        let layout = UICollectionViewCompositionalLayout(
            sectionProvider: sectionProvider, configuration: config)
        layout.register(
            SectionBackgroundDecorationView.self,
            forDecorationViewOfKind: SectionDecorationViewController.sectionBackgroundDecorationElementKind)
        return layout
    }
}

extension SectionDecorationViewController {
    func configureHierarchy() {
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        collectionView.backgroundColor = .systemBackground
    
        view.addSubview(collectionView)
        collectionView.delegate = self
    }
    func configureDataSource() {
        
        let cellRegistration = UICollectionView.CellRegistration<ListCell, Int> { (cell, indexPath, identifier) in
            // Populate the cell with our item description.

            cell.label.text = "\(indexPath.section),\(indexPath.item)"

        }
        
        dataSource = UICollectionViewDiffableDataSource<Int, Int>(collectionView: collectionView) {
            (collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in
            // Return the cell.
            return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
        }

        // initial data
        let itemsPerSection = 5
        let sections = Array(0..<5)
        currentSnapshot = NSDiffableDataSourceSnapshot<Int, Int>()
        var itemOffset = 0
        sections.forEach {
            currentSnapshot.appendSections([$0])
            currentSnapshot.appendItems(Array(itemOffset..<itemOffset + itemsPerSection))
            itemOffset += itemsPerSection
        }
        dataSource.apply(currentSnapshot, animatingDifferences: false)
    }
}

enter image description here

ios uicollectionview uicollectionviewcompositionallayout uicollectionreusableview
1个回答
0
投票

基于这个答案 - https://stackoverflow.com/a/77297540/6257435 - 只需进行一些修改,并在

.scrollDirection = .horizontal
...

时进行精简以强调群体背景

Simple Cell 类 - 单标签,居中:

class SimpleCell: UICollectionViewCell {
    
    let theLabel: UILabel = {
        let v = UILabel()
        v.textAlignment = .center
        return v
    }()
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        theLabel.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(theLabel)
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            theLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            theLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            theLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            theLabel.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
        
        contentView.layer.borderColor = UIColor(white: 0.5, alpha: 1.0).cgColor
        contentView.layer.borderWidth = 1.0
        contentView.layer.cornerRadius = 6
        contentView.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
    }
    
}

部分背景视图类:

class SectionBackgroundView: UICollectionReusableView {
    
    static let reuseIdentifier: String = "SectionBackgroundView"
    
    let bkgView = UIView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    
    func commonInit() {
        backgroundColor = .clear
        
        bkgView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(bkgView)
        
        NSLayoutConstraint.activate([
            bkgView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0),
            bkgView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0),
            bkgView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0),
            bkgView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0),
        ])
        
        bkgView.backgroundColor = .init(red: 0.5, green: 0.75, blue: 1.0, alpha: 1.0)
        bkgView.layer.cornerRadius = 8.0
        bkgView.layer.borderColor = UIColor.black.cgColor
        bkgView.layer.borderWidth = 1.0
    }
    
}

示例控制器类:

class HorizontalGroupsVC: UIViewController, UICollectionViewDelegate {
    
    var collectionView: UICollectionView!
    
    var dataSource: UICollectionViewDiffableDataSource<Int, Int>! = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: createLayout())
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(collectionView)
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
            collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            collectionView.heightAnchor.constraint(equalToConstant: 120.0),
        ])
        
        configureDataSource()
        
        collectionView.delegate = self
        
        view.backgroundColor = .systemYellow
        collectionView.backgroundColor = .clear
    }
    
    static let backgroundElementKind = "background-element-kind"
    
    func createLayout() -> UICollectionViewLayout {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                              heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        
        let groupSize = NSCollectionLayoutSize(widthDimension: .estimated(80.0),
                                               heightDimension: .fractionalHeight(1.0))
        
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        
        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = 8
        section.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)
        
        section.decorationItems = [
            NSCollectionLayoutDecorationItem.background(elementKind: HorizontalGroupsVC.backgroundElementKind)
        ]
        
        let config = UICollectionViewCompositionalLayoutConfiguration()
        config.interSectionSpacing = 12
        
        config.scrollDirection = .horizontal
        
        let layout = UICollectionViewCompositionalLayout(section: section, configuration: config)
        
        layout.register(SectionBackgroundView.self, forDecorationViewOfKind: HorizontalGroupsVC.backgroundElementKind)
        
        return layout
    }
    
    func configureDataSource() {
        
        let cellRegistration = UICollectionView.CellRegistration<SimpleCell, Int> { (cell, indexPath, identifier) in
            cell.theLabel.text = "\(indexPath)"
        }
        
        dataSource = UICollectionViewDiffableDataSource<Int, Int>(collectionView: collectionView) {
            (collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in
            return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
        }
        
        // initial data
        let itemsPerSection: [Int] = [3, 2, 1, 5, 3, 4, 2, 3, 4]
        let sections = Array(0..<itemsPerSection.count)
        var snapshot = NSDiffableDataSourceSnapshot<Int, Int>()
        var itemOffset = 0
        var i: Int = 0
        
        sections.forEach {
            snapshot.appendSections([$0])
            let n = itemsPerSection[i % itemsPerSection.count]
            snapshot.appendItems(Array(itemOffset..<itemOffset + n))
            itemOffset += n
            i += 1
        }
        
        dataSource.apply(snapshot, animatingDifferences: false)
    }
    
}

输出:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.