UIkit中使用新版UICollectionViewCompositionalLayout进行复杂布局(二)
文章目录
- 一、前言
- 二、示例代码
一、前言
此前使用UICollectionViewCompositionalLayout
进行了简单使用,下面对此进行复杂布局使用,效果如下
二、示例代码
import UIKit
// MARK: - 数据模型
struct Product { let name: String }
struct Banner { let title: String }
struct User { let username: String }// 新增模型,用于示例
struct SpecialItem { let title: String }// MARK: - Section 类型
enum SectionType {case products([Product])case banners([Banner])case users([User])case mixedGroupsSection // 同一 Section 中不同 Groupcase mixedItemsSection // 同一 Group 中不同 Item
}class SucViewController: UIViewController {var sections: [SectionType] = [.products([Product(name: "🍎"), Product(name: "🍌"), Product(name: "🍓"), Product(name: "🍇")]),.banners([Banner(title: "限时优惠"), Banner(title: "新品上市")]),.users([User(username: "Alice"), User(username: "Bob"), User(username: "Charlie")]),.mixedGroupsSection,.mixedItemsSection]private lazy var collectionView: UICollectionView = {let layout = createLayout()let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)cv.backgroundColor = .systemBackgroundcv.dataSource = selfcv.delegate = selfcv.register(ProductCell.self, forCellWithReuseIdentifier: "ProductCell")cv.register(BannerCell.self, forCellWithReuseIdentifier: "BannerCell")cv.register(UserCell.self, forCellWithReuseIdentifier: "UserCell")cv.register(SpecialCell.self, forCellWithReuseIdentifier: "SpecialCell")cv.translatesAutoresizingMaskIntoConstraints = falsereturn cv}()override func viewDidLoad() {super.viewDidLoad()view.addSubview(collectionView)NSLayoutConstraint.activate([collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])}// MARK: - Compositional Layoutfunc createLayout() -> UICollectionViewCompositionalLayout {return UICollectionViewCompositionalLayout { [weak self] sectionIndex, _ -> NSCollectionLayoutSection? inguard let self = self else { return nil }let sectionType = self.sections[sectionIndex]switch sectionType {case .products:let item = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .absolute(100)))item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)let group = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(100)),subitems: [item, item])return NSCollectionLayoutSection(group: group)case .banners:let item = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .absolute(120)))item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)let group = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .absolute(120)),subitems: [item])let section = NSCollectionLayoutSection(group: group)section.orthogonalScrollingBehavior = .continuousreturn sectioncase .users:let item = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(60)))item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10)let group = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(60)),subitems: [item])return NSCollectionLayoutSection(group: group)case .mixedGroupsSection:// 同一 Section 内不同 Grouplet item1 = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(80)))item1.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10)let item2 = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(120)))item2.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10)let group1 = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(80)),subitems: [item1])let group2 = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(120)),subitems: [item2])let mixGroup = NSCollectionLayoutGroup.vertical(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(200)),subitems: [group1, group2])let section = NSCollectionLayoutSection(group: mixGroup)return sectioncase .mixedItemsSection:// 同一 Group 内不同 Item(高度不同)let item1 = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .absolute(80)))item1.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)let item2 = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .absolute(120)))item2.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)let group = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(120)),subitems: [item1, item2])return NSCollectionLayoutSection(group: group)}}}
}// MARK: - 数据源
extension SucViewController: UICollectionViewDataSource {func numberOfSections(in collectionView: UICollectionView) -> Int { sections.count }func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {switch sections[section] {case .products(let items): return items.countcase .banners(let items): return items.countcase .users(let items): return items.countcase .mixedGroupsSection: return 2 // group 数量case .mixedItemsSection: return 2 // item 数量}}func collectionView(_ collectionView: UICollectionView,cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {switch sections[indexPath.section] {case .products(let items):let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProductCell", for: indexPath) as! ProductCellcell.configure(with: items[indexPath.item].name)return cellcase .banners(let items):let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerCell", for: indexPath) as! BannerCellcell.configure(with: items[indexPath.item].title)return cellcase .users(let items):let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UserCell", for: indexPath) as! UserCellcell.configure(with: items[indexPath.item].username)return cellcase .mixedGroupsSection:let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SpecialCell", for: indexPath) as! SpecialCellcell.configure(with: "Group \(indexPath.item+1)")return cellcase .mixedItemsSection:let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SpecialCell", for: indexPath) as! SpecialCellcell.configure(with: "Item \(indexPath.item+1)")return cell}}
}// MARK: - Delegate
extension SucViewController: UICollectionViewDelegate { }// MARK: - 新增 Cell
class SpecialCell: UICollectionViewCell {private let label = UILabel()override init(frame: CGRect) {super.init(frame: frame)contentView.backgroundColor = .systemPurplecontentView.layer.cornerRadius = 12contentView.clipsToBounds = truelabel.translatesAutoresizingMaskIntoConstraints = falselabel.textAlignment = .centerlabel.font = .boldSystemFont(ofSize: 18)label.textColor = .whitecontentView.addSubview(label)NSLayoutConstraint.activate([label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)])}required init?(coder: NSCoder) { fatalError() }func configure(with text: String) { label.text = text }
}// MARK: - Cell
class ProductCell: UICollectionViewCell {private let label = UILabel()override init(frame: CGRect) {super.init(frame: frame)contentView.backgroundColor = .systemBluecontentView.layer.cornerRadius = 12contentView.clipsToBounds = truelabel.translatesAutoresizingMaskIntoConstraints = falselabel.textAlignment = .centerlabel.font = .boldSystemFont(ofSize: 20)contentView.addSubview(label)NSLayoutConstraint.activate([label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)])}required init?(coder: NSCoder) { fatalError() }func configure(with text: String) { label.text = text }
}class BannerCell: UICollectionViewCell {private let label = UILabel()override init(frame: CGRect) {super.init(frame: frame)contentView.backgroundColor = .systemOrangecontentView.layer.cornerRadius = 12contentView.clipsToBounds = truelabel.translatesAutoresizingMaskIntoConstraints = falselabel.textAlignment = .centerlabel.font = .boldSystemFont(ofSize: 18)contentView.addSubview(label)NSLayoutConstraint.activate([label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)])}required init?(coder: NSCoder) { fatalError() }func configure(with text: String) { label.text = text }
}class UserCell: UICollectionViewCell {private let label = UILabel()override init(frame: CGRect) {super.init(frame: frame)contentView.backgroundColor = .systemGreencontentView.layer.cornerRadius = 12contentView.clipsToBounds = truelabel.translatesAutoresizingMaskIntoConstraints = falselabel.textAlignment = .centerlabel.font = .boldSystemFont(ofSize: 18)contentView.addSubview(label)NSLayoutConstraint.activate([label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)])}required init?(coder: NSCoder) { fatalError() }func configure(with text: String) { label.text = text }
}