I have two collection views, layered one on top of the other in my ViewController. The collection view on top is a horizontal scrolling collection view, while the one underneath scrolls vertically. I'm trying to create an effect where scrolling the lower collection view will cause it to move upwards to cover the upper collection view, like a sort of parallax effect.
I managed to get the effect by pinning both views to the top of the screen and modifying the lower collection view's content inset when scrolling, but this approach means that I cannot interact with the upper collection view, even when it's exposed. I'm looking for either a modification to this method, or a new method, that would allow me to retain this effect as well as interact with the upper collection view. Any suggestions on how to approach this problem? Thanks.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollView.contentInset.top = max(0, min(tendToSoon.frame.height, -scrollView.contentOffset.y))
}
Add two collectionviews in the view controller and set contentInset.top
to height of the first colletionview. And contentOffset.y
to minus value of contentInset.top
. And override point(inside:with:)
and return true only if y value is greater than 0.
Make sure the second collectionview's background color is clear.
class ViewController: UIViewController {
let topCollectionTitle = UILabel()
let topCollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewLayout())
let bottomCollectionView = BottomCollectionView(frame: .zero, collectionViewLayout: UICollectionViewLayout())
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
topCollectionTitle.textAlignment = .center
topCollectionTitle.text = "Top Collectionview"
topCollectionTitle.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(topCollectionTitle)
let topLayout = UICollectionViewFlowLayout()
topLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
topLayout.itemSize = CGSize(width: self.view.bounds.width / 5, height: 150)
topLayout.scrollDirection = .horizontal
topLayout.minimumLineSpacing = 0
topLayout.minimumInteritemSpacing = 0
topCollectionView.contentInsetAdjustmentBehavior = .never
topCollectionView.collectionViewLayout = topLayout
topCollectionView.backgroundColor = .white
topCollectionView.register(CellHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "CellHeader")
topCollectionView.register(ImgCell.self, forCellWithReuseIdentifier: "ImgCell")
topCollectionView.delegate = self
topCollectionView.dataSource = self
topCollectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(topCollectionView)
let bottomLayout = UICollectionViewFlowLayout()
bottomLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
bottomLayout.itemSize = CGSize(width: self.view.bounds.width / 2, height: 150)
bottomLayout.scrollDirection = .vertical
bottomLayout.minimumLineSpacing = 0
bottomLayout.minimumInteritemSpacing = 0
bottomLayout.headerReferenceSize = CGSize(width: 50, height: 50)
bottomCollectionView.collectionViewLayout = bottomLayout
bottomCollectionView.backgroundColor = .clear
bottomCollectionView.register(CellHeader.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "CellHeader")
bottomCollectionView.register(ImgCell.self, forCellWithReuseIdentifier: "ImgCell")
bottomCollectionView.delegate = self
bottomCollectionView.dataSource = self
bottomCollectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(bottomCollectionView)
bottomCollectionView.contentInset.top = 200
bottomCollectionView.contentOffset.y = -200
topCollectionTitle.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[topCollectionView]|", options: [], metrics: nil, views: ["topCollectionView":topCollectionView]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:[topCollectionTitle(30)][topCollectionView(200)]", options: [], metrics: nil, views: ["topCollectionView":topCollectionView,"topCollectionTitle":topCollectionTitle]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(10)-[topCollectionTitle]|", options: [], metrics: nil, views: ["topCollectionTitle":topCollectionTitle]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[bottomCollectionView]|", options: [], metrics: nil, views: ["bottomCollectionView":bottomCollectionView]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[bottomCollectionView]|", options: [], metrics: nil, views: ["bottomCollectionView":bottomCollectionView]))
}
}
extension ViewController: UICollectionViewDelegate {
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 25
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImgCell", for: indexPath) as? ImgCell ?? ImgCell()
cell.imgView.backgroundColor = .red
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "CellHeader", for: indexPath) as? CellHeader
if collectionView == bottomCollectionView {
header?.titleLbl.text = "Bottom CollectionView"
}
return header!
}
return UICollectionReusableView()
}
}
class ImgCell: UICollectionViewCell {
let imgView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
func setupViews() {
backgroundColor = .white
imgView.layer.cornerRadius = 5.0
imgView.layer.masksToBounds = true
imgView.translatesAutoresizingMaskIntoConstraints = false
addSubview(imgView)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(5)-[imgView]-(5)-|", options: [], metrics: nil, views: ["imgView":imgView]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(5)-[imgView]-(5)-|", options: [], metrics: nil, views: ["imgView":imgView]))
}
}
class CellHeader: UICollectionReusableView {
let titleLbl = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
func setupViews() {
backgroundColor = .white
titleLbl.textAlignment = .center
titleLbl.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLbl)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[titleLbl]|", options: [], metrics: nil, views: ["titleLbl":titleLbl]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[titleLbl]|", options: [], metrics: nil, views: ["titleLbl":titleLbl]))
}
}
class BottomCollectionView:UICollectionView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return point.y > 0
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With