I'm trying to transition my collection view between a horizontal film-strip layout and a vertical stack layout.
This is what I'm currently doing:
- Using
setCollectionViewLayout(_:animated:completion:)to transition between horizontal and vertical scroll direction - Changing the height constraint of the collection view, along with
UIView.animateandself.view.layoutIfNeeded()
The animation from film-strip to vertical stack is fine. However, the animation from vertical stack to film-strip is broken. Here's what it looks like:
If I make collectionViewHeightConstraint 300 by default, and remove these lines:
collectionViewHeightConstraint.constant = 300
collectionViewHeightConstraint.constant = 50
... the transition animation is fine both ways. However, there is excess spacing, and I want the film-strip layout to only be in 1 row.
How can I make the animation be smooth both ways? Here's my code (link to the demo project):
class ViewController: UIViewController {
var isExpanded = false
var verticalFlowLayout = UICollectionViewFlowLayout()
var horizontalFlowLayout = UICollectionViewFlowLayout()
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!
@IBAction func toggleExpandPressed(_ sender: Any) {
isExpanded.toggle()
if isExpanded {
collectionView.setCollectionViewLayout(verticalFlowLayout, animated: true) /// set vertical scroll
collectionViewHeightConstraint.constant = 300 /// make collection view height taller
} else {
collectionView.setCollectionViewLayout(horizontalFlowLayout, animated: true) /// set horizontal scroll
collectionViewHeightConstraint.constant = 50 /// make collection view height shorter
}
/// animate the collection view's height
UIView.animate(withDuration: 1) {
self.view.layoutIfNeeded()
}
/// Bonus points:
/// This makes the animation way more worse, but I would like to be able to scroll to a specific IndexPath during the transition.
// collectionView.scrollToItem(at: IndexPath(item: 9, section: 0), at: .bottom, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
verticalFlowLayout.scrollDirection = .vertical
horizontalFlowLayout.scrollDirection = .horizontal
collectionView.collectionViewLayout = horizontalFlowLayout
collectionView.dataSource = self
collectionView.delegate = self
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
/// if expanded, cells should be full-width
/// if not expanded, cells should have a width of 50
return isExpanded ? CGSize(width: collectionView.frame.width, height: 50) : CGSize(width: 100, height: 50)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0 /// no spacing needed for now
}
}
/// sample data source
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ID", for: indexPath)
cell.contentView.layer.borderWidth = 5
cell.contentView.layer.borderColor = UIColor.red.cgColor
return cell
}
}



