I'm trying to accomplish a dynamic cell with the new collection view compositional layout
basically this is what I have:
I have tried two approaches:
1- Adding the inner collection views inside a vertical stack,
2- Adding the inner collection views inside the container view with constraints
This is what I have currently:
The top UICollectionView (Compositional Layout)
func setupCollectionViewLayout() -> UICollectionViewLayout {
let size = NSCollectionLayoutSize(
widthDimension: NSCollectionLayoutDimension.fractionalWidth(1),
heightDimension: NSCollectionLayoutDimension.estimated(300)
)
let item = NSCollectionLayoutItem(layoutSize: size)
let group = NSCollectionLayoutGroup.vertical(layoutSize: size, subitem: item, count: 1)
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = .zero
section.interGroupSpacing = 0
let headerFooterSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.3)
)
let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerFooterSize,
elementKind: UICollectionView.elementKindSectionHeader,
alignment: .top
)
section.boundarySupplementaryItems = [sectionHeader]
return UICollectionViewCompositionalLayout(section: section)
}
The Cell (Using Container View Constraints)
class FeedsCell: UICollectionViewCell {
@IBOutlet weak var containerView: UIView!
@IBOutlet weak var innerStackView: UIStackView!
@IBOutlet weak var postDescription: UILabel!
var imageGalleryCollectionView: UICollectionView!
var reactionCollectionView: UICollectionView!
var commentCollectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
}
func with(viewModel: FeedsCellViewModel) -> Self {
postDescription.text = ".random(in: 0...255)"
if !viewModel.imageProvider.dataSource.isEmpty {
let imageLayout = setupImageLayout()
imageGalleryCollectionView = UICollectionView(frame: .zero, collectionViewLayout: imageLayout)
imageGalleryCollectionView.delegate = viewModel.imageProvider
imageGalleryCollectionView.dataSource = viewModel.imageProvider
containerView.addSubview(imageGalleryCollectionView)
}
if !viewModel.reactionProvider.dataSource.isEmpty {
let reactionLayout = UICollectionViewFlowLayout()
reactionLayout.scrollDirection = .horizontal
reactionCollectionView = UICollectionView(frame: .zero, collectionViewLayout: reactionLayout)
reactionCollectionView.showsHorizontalScrollIndicator = false
reactionCollectionView.dataSource = viewModel.reactionProvider
reactionCollectionView.delegate = viewModel.reactionProvider
innerStackView.addArrangedSubview(reactionCollectionView)
reactionCollectionView.anchor(heightConstant: 32)
}
if !viewModel.commentProvider.dataSource.isEmpty {
let commentLayout = setupCommentLayout()
commentCollectionView = UICollectionView(frame: .zero, collectionViewLayout: commentLayout)
commentCollectionView.dataSource = viewModel.commentProvider
commentCollectionView.delegate = viewModel.commentProvider
containerView.addSubview(commentCollectionView)
imageGalleryCollectionView.anchor(top: innerStackView.bottomAnchor, left: innerStackView.leftAnchor, bottom: commentCollectionView.topAnchor, right: innerStackView.rightAnchor)
commentCollectionView.anchor(top: imageGalleryCollectionView.bottomAnchor, left: innerStackView.leftAnchor, bottom: containerView.bottomAnchor, right: innerStackView.rightAnchor)
}
return self
}
override func prepareForReuse() {
super.prepareForReuse()
imageGalleryCollectionView?.removeFromSuperview()
reactionCollectionView?.removeFromSuperview()
commentCollectionView?.removeFromSuperview()
}
func setupCommentLayout() -> UICollectionViewCompositionalLayout {
let layout = UICollectionViewCompositionalLayout.list(using: .init(appearance: .insetGrouped))
return layout
}
func setupImageLayout() -> UICollectionViewCompositionalLayout {
let mainItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(2/3),
heightDimension: .fractionalHeight(1.0)))
mainItem.contentInsets = NSDirectionalEdgeInsets(
top: 2,
leading: 0,
bottom: 0,
trailing: 2)
let pairItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.5)))
pairItem.contentInsets = NSDirectionalEdgeInsets(
top: 2,
leading: 2,
bottom: 0,
trailing: 2)
let trailingGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1/3),
heightDimension: .fractionalHeight(1.0)),
subitem: pairItem,
count: 2)
let mainWithPairGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(4/9)),
subitems: [mainItem, trailingGroup])
let nestedGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalWidth(1.0)),
subitems: [
mainWithPairGroup,
]
)
let section = NSCollectionLayoutSection(group: nestedGroup)
return UICollectionViewCompositionalLayout(section: section)
}
}
<h1>The Result </h1>
The Cell (using UIStackView)
func with(viewModel: FeedsCellViewModel) -> Self {
postDescription.text = ".random(in: 0...255)"
if !viewModel.imageProvider.dataSource.isEmpty {
let imageLayout = setupImageLayout()
imageGalleryCollectionView = UICollectionView(frame: .zero, collectionViewLayout: imageLayout)
imageGalleryCollectionView.delegate = viewModel.imageProvider
imageGalleryCollectionView.dataSource = viewModel.imageProvider
innerStackView.addArrangedSubview(imageGalleryCollectionView)
}
if !viewModel.reactionProvider.dataSource.isEmpty {
let reactionLayout = UICollectionViewFlowLayout()
reactionLayout.scrollDirection = .horizontal
reactionCollectionView = UICollectionView(frame: .zero, collectionViewLayout: reactionLayout)
reactionCollectionView.showsHorizontalScrollIndicator = false
reactionCollectionView.dataSource = viewModel.reactionProvider
reactionCollectionView.delegate = viewModel.reactionProvider
innerStackView.addArrangedSubview(reactionCollectionView)
reactionCollectionView.anchor(heightConstant: 32)
}
if !viewModel.commentProvider.dataSource.isEmpty {
let commentLayout = setupCommentLayout()
commentCollectionView = UICollectionView(frame: .zero, collectionViewLayout: commentLayout)
commentCollectionView.dataSource = viewModel.commentProvider
commentCollectionView.delegate = viewModel.commentProvider
innerStackView.addArrangedSubview(commentCollectionView)
}
return self
}
<h1> The Result </h1>
It's really been a struggle, it's my 5th day trying to figure this out.