So I have a weird problem:
I’m building infinite carausel (collectionView) that needs to be in vertical scrollView.
When I try to embed collectionView with a horizontal scroll into a vertical scrollview when I start scrolling vertically, collectionview dissapears. This is simplified code of my component:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
private var scrollView: UIScrollView!
private var contentView: UIStackView!
private var collectionView: UICollectionView!
private var items = [UIColor.red, UIColor.green]
private var currentIndex: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
setupCollectionView()
}
private func setupScrollView() {
scrollView = UIScrollView()
scrollView.showsVerticalScrollIndicator = true
scrollView.alwaysBounceVertical = true
scrollView.delegate = self
view.addSubview(scrollView)
scrollView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
contentView = UIStackView()
contentView.axis = .vertical
contentView.alignment = .center
scrollView.addSubview(contentView)
contentView.snp.makeConstraints { make in
make.edges.equalToSuperview()
make.width.equalToSuperview()
make.height.greaterThanOrEqualToSuperview()
}
}
private func setupCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(CarouselCell.self, forCellWithReuseIdentifier: CarouselCell.reuseIdentifier)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.isMultipleTouchEnabled = true
contentView.addArrangedSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview()
make.height.equalTo(200)
}
contentView.addArrangedSubview(horizontalStackView)
horizontalStackView.snp.makeConstraints { make in
make.top.equalTo(collectionView.snp.bottom).offset(20)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-20) // Ensure the stack view is within scroll view bounds
}
contentView.addArrangedSubview(UIView())
// Initialize starting position
DispatchQueue.main.async {
self.collectionView.scrollToItem(at: IndexPath(item: self.items.count * 10, section: 0), at: .centeredHorizontally, animated: false)
}
}
// MARK: - UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count * 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CarouselCell.reuseIdentifier, for: indexPath) as! CarouselCell
cell.cardView.backgroundColor = items[indexPath.item % items.count]
return cell
}
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return collectionView.bounds.size
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = scrollView.frame.width
let currentPage = scrollView.contentOffset.x / pageWidth
let numberOfItems = CGFloat(items.count * 20)
let pageIndex = Int(currentPage) % items.count
currentIndex = pageIndex
if currentPage < 1 {
scrollView.setContentOffset(CGPoint(x: pageWidth * (numberOfItems + currentPage), y: 0), animated: false)
} else if currentPage >= numberOfItems {
scrollView.setContentOffset(CGPoint(x: pageWidth * (currentPage - numberOfItems), y: 0), animated: false)
}
}
}
// Custom UICollectionViewCell
class CarouselCell: UICollectionViewCell {
static let reuseIdentifier = "CarouselCell"
let cardView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.layer.cornerRadius = 12
view.layer.masksToBounds = true
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
private func setup() {
contentView.addSubview(cardView)
// Add padding and set constraints for the cardView
NSLayoutConstraint.activate([
cardView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
cardView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10),
cardView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
cardView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10)
])
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Add any additional logic for the vertical scroll view if needed
}
}
Everything works fine if I remove scrollView but still I need its functionality. Please help.