dynamic height of UICollectionView (horizontal scrolling) based on cell height - ios

I've got the following situation:
A collectionView inside a containerView that sits below the navigationBar. The view is set up programmatically (no xib).
I want to place the containerView in a way that it does not need a height constraint. Is that possible? The containerView should get it's height based on the constraints in the collectionView cells.
Code:
This is the function which lays out the containerView inside the viewController:
private func setUpContainerView() {
view.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
containerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20)
])
}
Inside the containerView (which is a subclass of UIView), the collectionView is set up like that (called in the init of that class):
private func setUpCollectionView() {
collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: collectionViewFlowLayout())
guard let collectionView = collectionView else { return }
addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
collectionView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
collectionView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
collectionView.topAnchor.constraint(equalTo: self.topAnchor)
])
collectionView.delegate = self
collectionView.dataSource = self
registerCollectionViewNibs()
}
private func collectionViewFlowLayout() -> UICollectionViewFlowLayout{
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.minimumInteritemSpacing = 10
flowLayout.minimumLineSpacing = 10
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
return flowLayout
}
When I do it like that, the collectionView is not visible. It only shows up when I add a height constraint with a specific constant to the containerView (inside the setUpContainerView function).
The problem is, that I don't know that height. I would have to set that height to 10+10+50 = 70 manually. But I want to make the containerView get it's size based on the collectionView cell constraints. Is that possible?

Related

UIScrollVIew not Scrolling Vertically programatically no matter what

I have been trying to scroll the view for a whole day yesterday and I am not able to figure out why it won't scroll. I am not sure what I am doing wrong !!
I have looked at the solutions on stackoverflow:
UIScrollView Scrollable Content Size Ambiguity
How to append a character to a string in Swift?
Right anchor of UIScrollView does not apply
But still, the view doesn't scroll and the scrollview height should be equal to the conrainerView height. But in my case, it stays fixed to the height of the view.
Here is the code repo: https://bitbucket.org/siddharth_shekar/ios_colttestproject/src/master/
Kindly go through and any help would be appreciated. Thanks!!
Here is the code Snippet as well, If you want to go through the constraints and see if there is anything I have added which is not letting the scroll view do its thing !!
I have made changes to the view just one looong text and removed other images, labels, etc to produce the minimal reproducable code.
And I looked at this persons project as well. Their view scrolls!!
https://useyourloaf.com/blog/easier-scrolling-with-layout-guides/
I am just not sure what I am doing differently!!!!
Here is my code for the contentView. It is literally just a textlabel
import Foundation
import UIKit
class RecipeUIView: UIView{
private var recipeTitle: UILabel! = {
let label = UILabel()
label.numberOfLines = 0
label.font = .systemFont(ofSize: 24, weight: .bold)
label.textColor = .gray
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.adjustsFontForContentSizeCategory = true
return label
}()
func setupView(currentRecipe: Receipe?){
recipeTitle.text = currentRecipe?.dynamicTitle
addSubview(recipeTitle)
let margin = readableContentGuide
// Constraints
recipeTitle.topAnchor.constraint(equalTo: margin.topAnchor, constant: 4).isActive = true
recipeTitle.leadingAnchor.constraint(equalTo: margin.leadingAnchor, constant: 20).isActive = true
recipeTitle.trailingAnchor.constraint(equalTo: margin.trailingAnchor, constant: -20).isActive = true
}
}
And here is the viewController
import Foundation
import UIKit
class RecipeViewController: UIViewController {
var selectedRecipe: Receipe?
let recipeView: RecipeUIView = {
let view = RecipeUIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
override func viewDidLoad() {
super.viewDidLoad()
recipeView.setupView(currentRecipe: selectedRecipe)
recipeView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20)
view.addSubview(scrollView)
scrollView.addSubview(recipeView)
let frameGuide = scrollView.frameLayoutGuide
let contentGuide = scrollView.contentLayoutGuide
// Scroll view layout guides (iOS 11)
NSLayoutConstraint.activate([
frameGuide.leadingAnchor.constraint(equalTo: view.leadingAnchor),
frameGuide.topAnchor.constraint(equalTo: view.topAnchor),
frameGuide.trailingAnchor.constraint(equalTo: view.trailingAnchor),
frameGuide.bottomAnchor.constraint(equalTo: view.bottomAnchor),
contentGuide.leadingAnchor.constraint(equalTo: recipeView.leadingAnchor),
contentGuide.topAnchor.constraint(equalTo: recipeView.topAnchor),
contentGuide.trailingAnchor.constraint(equalTo: recipeView.trailingAnchor),
contentGuide.bottomAnchor.constraint(equalTo: recipeView.bottomAnchor),
contentGuide.widthAnchor.constraint(equalTo: frameGuide.widthAnchor),
])
}
}
And I am still not able to scroll the view. Here is a screenshot of my project output. Still no scroll guide lines on the right!!
UPDATE:: Now the text scrolls, but when I add a UITableView in the UIView the scrolling works but the tableView is not seen in the UiView.
Is it due to the constraints again???
here is the code for the same::
class RecipeUIView: UIView, UITableViewDelegate, UITableViewDataSource{
var currentRecipe: Receipe?
private let tableView: UITableView = {
let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
tableView.backgroundColor = .green
return tableView
}()
private var recipeTitle: UILabel! = {
let label = UILabel()
label.numberOfLines = 0
label.font = .systemFont(ofSize: 24, weight: .bold)
label.textColor = .gray
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.adjustsFontForContentSizeCategory = true
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("++++ IngrediantsTableViewCell tableview count: \(currentRecipe?.ingredients.count ?? 0)")
return currentRecipe?.ingredients.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("++++ IngrediantsTableViewCell tableview cellForRow ")
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
cell.textLabel!.text = "\(currentRecipe?.ingredients[indexPath.row].ingredient ?? "")"
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//return UITableView.automaticDimension
return 30
}
func setupView(currentRecipe: Receipe?){
let margin = readableContentGuide
self.currentRecipe = currentRecipe
recipeTitle.text = currentRecipe?.dynamicTitle
addSubview(recipeTitle)
// Constraints
recipeTitle.topAnchor.constraint(equalTo: margin.topAnchor, constant: 4).isActive = true
recipeTitle.leadingAnchor.constraint(equalTo: margin.leadingAnchor, constant: 20).isActive = true
recipeTitle.trailingAnchor.constraint(equalTo: margin.trailingAnchor, constant: -20).isActive = true
addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: recipeTitle.bottomAnchor, constant: 10).isActive = true
tableView.leadingAnchor.constraint(equalTo: margin.leadingAnchor, constant: 20).isActive = true
tableView.trailingAnchor.constraint(equalTo: margin.trailingAnchor, constant: -20).isActive = true
tableView.bottomAnchor.constraint(equalTo: margin.bottomAnchor, constant: -20).isActive = true
tableView.reloadData()
}
}
You are missing a constraint...
In your RecipeUIView class, you have this:
func setupView(currentRecipe: Receipe?){
recipeTitle.text = currentRecipe?.dynamicTitle
addSubview(recipeTitle)
let margin = readableContentGuide
// Constraints
recipeTitle.topAnchor.constraint(equalTo: margin.topAnchor, constant: 4).isActive = true
recipeTitle.leadingAnchor.constraint(equalTo: margin.leadingAnchor, constant: 20).isActive = true
recipeTitle.trailingAnchor.constraint(equalTo: margin.trailingAnchor, constant: -20).isActive = true
}
So, you have no constraint controlling the view's Height.
Add this line:
recipeTitle.bottomAnchor.constraint(equalTo: margin.bottomAnchor, constant: -20).isActive = true
And you'll get vertical scrolling.
Two side notes...
First, in ``RecipeViewController`, change your constraints like this:
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
recipeView.leadingAnchor.constraint(equalTo: contentGuide.leadingAnchor),
recipeView.topAnchor.constraint(equalTo: contentGuide.topAnchor),
recipeView.trailingAnchor.constraint(equalTo: contentGuide.trailingAnchor),
recipeView.bottomAnchor.constraint(equalTo: contentGuide.bottomAnchor),
recipeView.widthAnchor.constraint(equalTo: frameGuide.widthAnchor),
])
There's no real functional difference, but it is more logical and more readable to think in terms of:
I'm constraining the scrollView to the view
I'm constraining the recipeView to the scroll view's .contentLayoutGuide (which determines the "scrollable" size)
I'm constraining the recipeView width the the scroll view's .frameLayoutGuide
Second, giving views contrasting background colors can be very helpful when trying to debug layouts.
For example, if I set background colors like this:
recipeTitle label : cyan
recipeView : yellow
scrollView : orange
It looks like this when running (with your original constraints):
Since the cyan label is a subview of the yellow view, it is obvious that the yellow view height is not correct.
After add the missing bottom constraint, it looks like this:

(Swift 5) UIScrollView scrolls but none of the content scrolls (video included)

I'm trying to learn to build views without storyboard. I tried to build a scrollview. On that scrollview is a UISearchBar, a UIImageView with an image and a UILabel. It works but none of the content moves. The content is all just frozen in place like no matter how far I scroll the search bar will always be on top of the page. and the image on the bottom. I've attached a video to show what I mean. There's also a problem because none of the content is where I want it to be but that's another problem. I realize this is probably because I don't know enough about constraints and autolayout and building views without storyboards.
Here's the video
class HomePageViewController: UIViewController {
var searchedText: String = ""
let label = UILabel()
let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.placeholder = "Where are you going?"
searchBar.translatesAutoresizingMaskIntoConstraints = false
searchBar.barTintColor = .systemCyan
searchBar.searchTextField.backgroundColor = .white
searchBar.layer.cornerRadius = 5
return searchBar
}()
let homeImage: UIImageView = {
let homeImage = UIImageView()
homeImage.translatesAutoresizingMaskIntoConstraints = false
homeImage.clipsToBounds = true
return homeImage
}()
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .systemMint
scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 30)
return scrollView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemPink
// setupLayout()
// tried this here doesn't do anything for me
}
func setupLayout() {
view.addSubview(scrollView)
self.scrollView.addSubview(searchBar)
homeImage.image = UIImage(named: "Treehouse")
self.scrollView.addSubview(homeImage)
label.text = "Inspiration for your next trip..."
self.scrollView.addSubview(label)
// not sure where this label is being added I want it to be underneath the image but it isn't t
let safeG = view.safeAreaLayoutGuide
let viewFrame = view.bounds
NSLayoutConstraint.activate([
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: -10),
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
searchBar.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 50.0),
searchBar.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 0.9),
searchBar.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
homeImage.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 150),
homeImage.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 1.1),
homeImage.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
homeImage.heightAnchor.constraint(equalToConstant: viewFrame.height/2),
label.topAnchor.constraint(equalTo: homeImage.bottomAnchor, constant: 100)
])
// was doing all this in viewDidLayoutSubviews but not sure if this is better place for it
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setupLayout()
// tried this in viewDidLoad() and it didn't solve it.
}
}
any help would be appreciated
First, when constraining subviews in a UIScrollView, you should constrain them to the scroll view's Content Layout Guide. You're constraining them to the view's safe area layout guide, so they're never going to go anywhere.
Second, it's difficult to center subviews in a scroll view, because the scroll view can scroll both horizontally and vertically. So it doesn't really have a "center."
You can either put subviews in a stack view, or, quite common, use a UIView as a "content" view to hold the subviews. If you constrain that content view's Width to the scroll view's Frame Layout Guide width, you can then horizontally center the subviews.
Third, it can be very helpful to comment your constraints, so you know exactly what you expect them to do.
Here's a modified version of your posted code:
class HomePageViewController: UIViewController {
var searchedText: String = ""
let label: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.placeholder = "Where are you going?"
searchBar.translatesAutoresizingMaskIntoConstraints = false
searchBar.barTintColor = .systemCyan
searchBar.searchTextField.backgroundColor = .white
searchBar.layer.cornerRadius = 5
return searchBar
}()
let homeImage: UIImageView = {
let homeImage = UIImageView()
homeImage.translatesAutoresizingMaskIntoConstraints = false
homeImage.clipsToBounds = true
return homeImage
}()
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .systemMint
// don't do this
//scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 30)
return scrollView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemPink
setupLayout()
}
func setupLayout() {
view.addSubview(scrollView)
//homeImage.image = UIImage(named: "Treehouse")
homeImage.image = UIImage(named: "natureBKG")
label.text = "Inspiration for your next trip..."
// let's use a UIView to hold the "scroll content"
let contentView = UIView()
contentView.translatesAutoresizingMaskIntoConstraints = false
// give it a green background so we can see it
contentView.backgroundColor = .green
contentView.addSubview(searchBar)
contentView.addSubview(homeImage)
contentView.addSubview(label)
scrollView.addSubview(contentView)
let safeG = view.safeAreaLayoutGuide
let svContentG = scrollView.contentLayoutGuide
let svFrameG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain scrollView to all 4 sides of view
// (generally, constrain to safe-area, but this is what you had)
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
// constrain contentView to all 4 sides of scroll view's Content Layout Guide
contentView.topAnchor.constraint(equalTo: svContentG.topAnchor, constant: 0.0),
contentView.leadingAnchor.constraint(equalTo: svContentG.leadingAnchor, constant: 0.0),
contentView.trailingAnchor.constraint(equalTo: svContentG.trailingAnchor, constant: 0.0),
contentView.bottomAnchor.constraint(equalTo: svContentG.bottomAnchor, constant: 0.0),
// constrain contentView Width equal to scroll view's Frame Layout Guide Width
contentView.widthAnchor.constraint(equalTo: svFrameG.widthAnchor),
// constrain searchBar Top to contentView Top + 50
searchBar.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 50.0),
// constrain searchBar Width to 90% of contentView Width
searchBar.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.9),
// constrain searchBar centerX to contentView centerX
searchBar.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
// constrain homeImage Top to searchBar Bottom + 40
homeImage.topAnchor.constraint(equalTo: searchBar.bottomAnchor, constant: 40.0),
// constrain homeImage Width equal to contentView Width
homeImage.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 1.0),
// constrain homeImage centerX to contentView centerX
homeImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
// constrain homeImage Height to 1/2 of scroll view frame Height
homeImage.heightAnchor.constraint(equalTo: svFrameG.heightAnchor, multiplier: 0.5),
// you probably won't get vertical scrolling yet, so increase the vertical space
// between the homeImage and the label by changing the constant
// from 100 to maybe 400
// constrain label Top to homeImage Bottom + 100
label.topAnchor.constraint(equalTo: homeImage.bottomAnchor, constant: 100.0),
// constrain label centerX to contentView centerX
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
// constrain label Bottom to contentView Bottom - 20
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20.0),
])
}
}

How to set Dynamically UIScrollView height in Swift 4 IOS?

If the height of scrollview not set. then scrollview will not scrollable.
To make it scrollable. I set height statically in code like this.
scrollView.contentSize = CGSize(width: self.view.frame.size.width, height: 1000)
Is there any way i can set height dynamically??
If you wanted to do with storyboard then first go through this.
If you wanted to do by code as you done it code then first you have to calculate the inner content height programatically the use the below code.
scrollView.contentSize = CGSize(width: self.view.frame.size.width, height: contentHeight)
Still have any query then ask.
One option using AutoLayout is to make UIStackView a subview of the UIScrollView. Set the constraints (leading, trailing, top, bottom and width) of UIStackView to be equal to UIScrollView. Set the height of the subviews (alternatively make them dynamic to resize depending on their own subviews). Then add the subviews to the UIStackView by using addArrangedSubview and it will handle the constraints for you. The UIScrollView's contentSize will adapt to the UIStackView depending on it's subviews.
Don't forget to change the axis property of UIStackView to vertical.
Here is an example using NSLayoutAnchor:
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let redView = UIView()
redView.backgroundColor = .red
redView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
redView.heightAnchor.constraint(equalToConstant: 400.0)
])
let blueView = UIView()
blueView.backgroundColor = .blue
blueView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
blueView.heightAnchor.constraint(equalToConstant: 700.0)
])
let scrollView = UIScrollView()
scrollView.backgroundColor = .black
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
let stackView = UIStackView()
stackView.axis = .vertical
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(redView)
stackView.addArrangedSubview(blueView)
scrollView.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
])
self.view = view
}
If you don't want to use UIStackView, just add every subview directly to UIScrollView and set the constraints how they relate to each other.

Disabling uicollectionview scroll makes uicollectionview smaller

I have got this uicollectionview
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 90
collectionView = UICollectionView(frame: CGRect(x:0,y:0,width:0,height:0), collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.isScrollEnabled = false
collectionView.heightAnchor.constraint(equalToConstant: collectionView.contentSize.height).isActive = true collectionView.topAnchor.constraint(equalTo:PostsTab.bottomAnchor).isActive = true
collectionView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
collectionView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
Now this collectionView is inside scrollView.On top of collectionview there is another view and it all looks like this
Now when i scroll down i want that UIView that is on top of collectionView to be left behind that's why i added isScrollEnabled = false,without that when i scroll down uiview stays on a fixed position
like this
override func viewDidAppear(_ animated: Bool) {
scrollView.contentSize = CGSize(width:1,height: 2400)
collectionView.heightAnchor.constraint(equalToConstant: collectionView.contentSize.height).isActive = true
}

How to use a slide animation rather than a "ghosting" animation when a UICollectionViewCell changes position due to a change in height of it's parent?

I'm building a UICollectionView which has two cells. When the user taps a button, the second cell needs to move from directly below the first cell to directly to the right of the first cell (off screen) and allow the user to scroll over to it.
The kicker is that I need it to appear to slide to the new position. Using my current code, it's just "ghosting".
Here's how I'm doing it now:
Initialize the UICollectionView with UICollectionViewFlowLayout with horizontal scrolling, paging enabled, and a height of two cells plus margin (196pt * 2 + 8pt = 400pt)
func setupTestCollectionView() {
// Create the layout, the frame, and the collection view
let testLayout = UICollectionViewFlowLayout()
let testFrame = CGRect()
let collectionView = UICollectionView(frame: testFrame, collectionViewLayout: testLayout)
// Specify the attributes of the elements we just created and add them to the primary view
testLayout.scrollDirection = UICollectionViewScrollDirection.horizontal
testLayout.minimumLineSpacing = 8
testLayout.minimumInteritemSpacing = 0
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.isPagingEnabled = true
collectionView.clipsToBounds = false
collectionView.backgroundColor = UIColor.green
collectionView.register(ArtworkCollectionViewCell.self, forCellWithReuseIdentifier: "artworkCell")
collectionView.delegate = self
collectionView.dataSource = self
view.addSubview(collectionView)
// Set all of the constraints to position the UICollectionView in the primary view then append them to the initialConstraints array
let topConstraint = collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8)
let leadingConstraint = collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0)
let trailingConstraint = collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0)
testHeightConstraint = collectionView.heightAnchor.constraint(equalToConstant: 400)
// testHeightConstraint is declared outside of this function so we can modify it in a different funcction when the user taps a button
initialConstraints.append(contentsOf: [topConstraint, leadingConstraint, trailingConstraint, testHeightConstraint])
}
Change the height constraint of the UICollectionView when the user taps a button to a height of 1 cell (196pt) and animate the layout update
func testButtonAction() {
// Change the height constraint of the UICollectionView
testHeightConstraint.constant = 196
// Animate the layout update
UIView.animate(withDuration: 0.2) {
self.view.layoutIfNeeded()
}
}
This achieves the function I'm looking for (see screenshots below), but so far I've been unable to figure out how to change the animation. Any help with this is greatly appreciated!
Thank you in advance!
Screenshot on View Load:
Screenshot after Button is Tapped:
Screenshot of Scrolling (to show functionality & position):

Resources