Swift: Create stack of imageView with collectionView - ios

Hey i want to create stack of UIImageView like the photo, how to do this
It must be dynamic. How can I move the cells so that they are one below the other?

Use UICollectionViewDelegateFlowLayout methods to make this kind of UI.
Example:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.white.cgColor
cell.layer.cornerRadius = 50.0
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.height, height: collectionView.bounds.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return -50
}
}
In the above code
Configure minimumLineSpacingForSectionAt and minimumInteritemSpacingForSectionAt methods of UICollectionViewDelegateFlowLayout.
Since the cell in collectionView are aligned left to right default, so to get the desired result we need to align them right to left.
As shown in above screenshot, use semantic property of collectionView for right to left alignment of cells.
Screenshot:
Edit-1:
One way to centre the cells in collectionView is to play with collectionView's width and centre it horizontally.
CollectionView constraints - top, width, centeredorizontally
In viewDidAppear, manually calculate the width of collectionView according to the numberOfItems. In your case numberOfItems = 3
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let width = min((collectionView.bounds.height) * CGFloat((numberOfItems-1)/2 + 1), UIScreen.main.bounds.width)
self.collectionViewWidthConstraint.constant = width
}

You can use UICollectionView Custom Layout .
Collection view layouts are subclasses of the abstract UICollectionViewLayout class. They define the visual attributes of every item in your collection view. The individual attributes are instances of UICollectionViewLayoutAttributes and contain the properties of each item in your collection view, such as the item’s frame or transform.
The similar Tutorial
This is a more complex layout , Change some parameters , you will get what you want.
Copyed from github , mpospese/IntroducingCollectionViews
translate some to Swift
class SpiralLayout: UICollectionViewLayout{
let itemSize: CGFloat = 170
var pageSize: CGSize!
var contentSize: CGSize!
var radius: CGFloat!
var cellCounts: [Int]!
var pageRects: [CGRect]!
var pageCount: Int!
override func prepare() {
super.prepare()
pageSize = collectionView?.bounds.size
let iPad = UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad
let scaleFactor: CGFloat = iPad ? 1 : 0.5
let side = itemSize * scaleFactor
radius = min(pageSize.width - side, pageSize.height - side * 1.2 )/2 - 5
pageCount = collectionView?.numberOfSections
var counts = [Int]()
var rects = [CGRect]()
for section in 0..<pageCount{
counts.append((collectionView?.numberOfItems(inSection: section))!)
rects.append(CGRect(origin: CGPoint(x: CGFloat(section) * pageSize.width, y: 0), size: pageSize))
}
cellCounts = counts
pageRects = rects
contentSize = CGSize(width: pageSize.width * CGFloat(pageCount), height: pageSize.height)
}
override var collectionViewContentSize: CGSize{
return contentSize
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return !pageSize.equalTo(newBounds.size)
}
func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
var attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.size = CGSize(width: itemSize, height: itemSize)
// ...
return attributes
}
}

Related

How to show three rounded images in Collectionview cell in all iPhone screen sizes in swift

I have taken collectionview in storyboard and in its cell i have taken ImageView and its below one label
i need to show only three rounded images horzontally and number of rows from JSON vertically in all screen sizes
like below image i need:
in cell for imageview costraints like below
leading = trailing = top = bottom = 5
and in coding:
class FriendsViewController: UIViewController {
// MARK: - IBOutlets
#IBOutlet weak var galleryCollectionView: UICollectionView!
// MARK: - LifeCycleMethods
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
layout.scrollDirection = .vertical
let width = UIScreen.main.bounds.width/4
let height = width*1.1
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 5
layout.itemSize = CGSize(width: width, height: height)
self.galleryCollectionView.collectionViewLayout = layout
}
}
class FriendsCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imgView: UIImageViewX!
#IBOutlet weak var lblTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
imgView.layer.cornerRadius = imgView.frame.height/2.0 }
}
so i am getting weird o/p in different screen sizes why?
o/p of ipodtouch7
In your collectionview cell Set constraints as shown in attached image, i.e. ur image view width should depend on imageview height, you can do it using ratio.
Then in willDisplay method calculate cornerRadius
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
{
guard let cell = cell as? TestCollectionViewCell else
{
return
}
let cellHeight : CGFloat = cell.frame.size.height
let labelHeight : CGFloat = cell.label?.frame.size.height ?? 0.0
cell.imageView?.layer.cornerRadius = (cellHeight - labelHeight) / 2.0
}
Below is the entire code
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
{
#IBOutlet weak var collectionView : UICollectionView? = nil
let horizontalSpaceBetweenCell : CGFloat = 16
let verticalSpaceBetweenCell : CGFloat = 16
let edgeInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
override func viewDidLoad()
{
super.viewDidLoad()
setup()
}
func setup()
{
let nib = UINib(nibName: "TestCollectionViewCell", bundle: nil)
collectionView?.register(nib, forCellWithReuseIdentifier: "TestCollectionViewCell")
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 40
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TestCollectionViewCell", for: indexPath) as? TestCollectionViewCell
{
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
{
guard let cell = cell as? TestCollectionViewCell else
{
return
}
let cellHeight : CGFloat = cell.frame.size.height
let labelHeight : CGFloat = cell.label?.frame.size.height ?? 0.0
cell.imageView?.layer.cornerRadius = (cellHeight - labelHeight) / 2.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
let numberOfCellsPerRow = 3
let otherSpace = (edgeInsets.left + edgeInsets.right)
let width = (collectionView.frame.size.width - otherSpace) / CGFloat(numberOfCellsPerRow)
return CGSize(width: width, height: 80) // Height can be anything 80, 90 ,100
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 16
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return edgeInsets
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
}
}
Please change Widhth to height :
imgView.layer.cornerRadius = imgView.frame.size.height/2.0

How to make Collection View cell more than one column?

Here the output of the code but I want to make it into 2 column
I want to make a collection view with more than 1 column but this code just shows one column. Can anyone help me how to fixed it??? Thank You....
import UIKit
class SearchViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
Here the array
var collectionArray : [String] = ["1", "2", "3", "4"]
let labelnamee = [("Long Sleeve Abstract Print Top"), ("Logo Graphic Print Top"), ("Material Study T-Shirt"), ("Mission Statement Print T-Shirt"), ("Printed Logo T-Shirt"), ("Tie-Dye Print T-Shirt")]
let labelpricee = [("RM 1021"), ("RM 860"), ("RM 750"), ("RM 750") , ("RM 670"), ("RM 760")]
let imagee = [UIImage(named: "abstractprint"),
UIImage(named: "longsleeve"),UIImage(named: "studymaterial"),UIImage(named: "mission"), UIImage(named: "white"), UIImage(named: "tiedye")]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return labelnamee.count
}
for the collection cell border
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let cellIndex = indexPath.item
cell.imageView.image = imagee[cellIndex]
cell.labelname.text = labelnamee[cellIndex]
cell.labelprice.text = labelpricee[cellIndex]
cell.contentView.layer.cornerRadius = 10
cell.contentView.layer.borderWidth = 1.0
cell.contentView.layer.borderColor = UIColor.blue.cgColor
cell.backgroundColor = UIColor.white
cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
cell.layer.shadowRadius = 2.0
cell.layer.shadowOpacity = 1.0
cell.layer.masksToBounds = false
cell.layer.shadowPath = UIBezierPath(roundedRect: cell.bounds, cornerRadius: cell.contentView.layer.cornerRadius).cgPath
return cell
}
}
Here the code for the layout. I think I made mistake in the height or weight..
extension SearchViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let bounds = collectionView.bounds
let heigtVal = self.view.frame.height
let widthVal = self.view.frame.width
let cellsize = (heigtVal < widthVal) ? bounds.height/2: bounds.width/2
return CGSize(width: cellsize - 10, height: cellsize - 10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
If the width of the cell or the contents of the cells is such that the collectionView cannot accommodate be able to see them within the visible portion of the screen, the collection view automatically places next to them. You have to scroll your collecctionView to see your next column.
If you want to see two columns within the visible screen portion, pls follow the steps:
Firstly place all your views inside a StackView and align them vertically.
Then set the right width & height constraints to your imageView to maintain the aspect ratio for your requirements. I have set like below just to demonstrate:
Along with the above constraints, I have also set the cell size to automatic in Storyboard itself rather than doing programmatically. Removed sizeForItemAt indexPath from code
:
Finally, after following all the above steps the output looked like this

HorizontalCollectionView Content width and spacing

How can I make my horizontal collection view labels width to wrap the content width of the label and make them have equal spacing between each of them? Currently I have the collection view cell width as 100. If I increase the width to fit other labels, the shorter labels have more spacing between them. Any ideas will be appreciated.
Calculate the width of the label text first with the font associated with the text.
extension String {
func size(with font: UIFont) -> CGSize {
let fontAttribute = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: fontAttribute)
return size
}
}
Return the calculated width along with collectionView height in collectionView(_, collectionViewLayout:_, sizeForItemAt).
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let newWidth = titles[indexPath.row].size(with: labelFont!).width + 10 //Added 10 to make the label visibility very clear
return CGSize(width: newWidth, height: collectionView.bounds.height)
}
Entire source code:
class ViewController: UIViewController {
#IBOutlet weak var collection: UICollectionView!
let labelFont = UIFont(name: "Helvetica Neue", size: 18)
let titles = ["Hi", "Hello", "HorizontalCollectionView", "VerticalCollectionView"]
override func viewDidLoad() {
super.viewDidLoad()
collection.backgroundColor = UIColor(red: 68/255, green: 143/255, blue: 1, alpha: 1)
collection.register(UINib.init(nibName: "CustomCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CustomCollectionViewCell")
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return titles.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10 // Adjust the inter item space based on the requirement.
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let newWidth = titles[indexPath.row].size(with: labelFont!).width + 10 //Added 10 to make the label visibility very clear
return CGSize(width: newWidth, height: collectionView.bounds.height)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath) as! CustomCollectionViewCell
cell.titleLabel.text = titles[indexPath.row]
cell.titleLabel.font = labelFont!
return cell
}
}
extension String {
func size(with font: UIFont) -> CGSize {
let fontAttribute = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: fontAttribute)
return size
}
}
Another Solution:
ViewController.swift
class ViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var collView: UICollectionView!
var tasksArray = ["To Do", "SHOPPING","WORK"]
var selectedIndex = Int()
override func viewDidLoad() {
super.viewDidLoad()
collView.register(UINib.init(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "Cell")
let layout = collView?.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = UICollectionViewFlowLayout.automaticSize
layout.estimatedItemSize = CGSize(width: 170, height: 50)
// Do any additional setup after loading the view, typically from a nib.
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tasksArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.lblName.text = tasksArray[indexPath.row]
if selectedIndex == indexPath.row
{
cell.backgroundColor = UIColor.lightGray
}
else
{
cell.backgroundColor = UIColor.white
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedIndex = indexPath.row
self.collView.reloadData()
}
}
Cell.swift
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var lblName: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
layer.borderWidth = 1
layer.cornerRadius = bounds.height / 2
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.width = ceil(size.width)
layoutAttributes.frame = frame
return layoutAttributes
}
}
You have to manually calculate the width of each cell. To calculate the width, you actually calculate the width of the text residing in that cell.
use following
boundingRect(with:options:attributes:context:)
https://developer.apple.com/documentation/foundation/nsstring/1524729-boundingrect
to calculate the width of a given string. So after calculating the returning the size the cell should be wrapping the text.
Now come the second part, equal spacing between items. use interItemSpacing to define the spacing between each cell.

How to align these collectionview cells properly?

I am creating a page where I use collection view. The layout will be like Apple's Music app where each row displays two square-shaped cells
I want a layout like this-this layout has super equal margins around but in my app the first collection cell is stuck to the left edge and the 2nd cell is stuck to the right edge
private let cellReuseIdentifier = "cellReuseIdentifier"
class FeedViewController: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
setupNavBar()
setupCollectionView()
}
func setupCollectionView() {
collectionView?.register(FeedCollectionViewCell.self, forCellWithReuseIdentifier: cellReuseIdentifier)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReuseIdentifier, for: indexPath)
return cell
}
}
extension FeedViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 25
let collectionViewSize = collectionView.frame.size.width - padding
return CGSize(width: collectionViewSize/2, height: collectionViewSize/2)
}
}
You can use the layout properties to set the collection view inset and the space you want between your cells, in your collection view setup function:
guard let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
layout.sectionInset = UIEdgeInsets(top: yourTopValue, left: yourLeftValue, bottom: yourBottomValue, right: yourRightValue)
layout.minimumInteritemSpacing = yourSpacing
layout.minimumLineSpacing = yourSpacing
Use following code to achieve your needs.
Padding value should be addition of all three spaces(Left, Center, Right)
Let's suppose padding value = 25 then it should consider 75 in layout calculation to get exact spacing.
And set left, top, center and right space with value 25(As you want to add space there).
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellWidth: CGFloat = (collectionView.frame.size.width / 2) - ((padding value * 3)/2)
let cellHeight: CGFloat = (collectionView.frame.size.height / 2) - ((padding value * 3)/2)
return CGSize.init(width: cellWidth, height: cellHeight)
}
Sure it will work

UICollectionView Custom Cell to fill width In Swift

I've been trying to figure-out how can i make the cell fill the width, as you can see in the picture the width between the cells is too big. i am using custom cell with only one imageView.
I tried to customize it from the storyboard but i guess there is no option for that or it should be done programmatically.
my UICollectionViewController :
#IBOutlet var collectionView2: UICollectionView!
let recipeImages = ["angry_birds_cake", "creme_brelee", "egg_benedict", "full_breakfast", "green_tea", "ham_and_cheese_panini", "ham_and_egg_sandwich", "hamburger", "instant_noodle_with_egg.jpg", "japanese_noodle_with_pork", "mushroom_risotto", "noodle_with_bbq_pork", "starbucks_coffee", "thai_shrimp_cake", "vegetable_curry", "white_chocolate_donut"]
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
//#warning Incomplete method implementation -- Return the number of sections
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//#warning Incomplete method implementation -- Return the number of items in the section
return recipeImages.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! RecipeCollectionViewCell
// Configure the cell
cell.recipeImageView.image = UIImage(named: recipeImages[indexPath.row])
return cell
}
You need to do this programatically.
Implement UICollectionViewDelegateFlowLayout in your view controller and provide the size in collectionView:layout:sizeForItemAtIndexPath:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let kWhateverHeightYouWant = 100
return CGSizeMake(collectionView.bounds.size.width, CGFloat(kWhateverHeightYouWant))
}
You will also want to call collectionView.collectionViewLayout.invalidateLayout() inside your view controller's viewWillLayoutSubviews() so that when the main view's dimensions change (on rotation, for example), the collection view is re-laid out.
Swift 4 Update
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let kWhateverHeightYouWant = 100
return CGSize(width: collectionView.bounds.size.width, height: CGFloat(kWhateverHeightYouWant))
}
Inside your view controller override viewDidLayoutSubviews method
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
let itemWidth = view.bounds.width / 3.0
let itemHeight = layout.itemSize.height
layout.itemSize = CGSize(width: itemWidth, height: itemHeight)
layout.invalidateLayout()
}
}
(collectionView property is your collectionView)
Use Following code for set the width of UICollectionViewCell.
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: screenWidth/3, height: screenWidth/3);
}
Also in Swift 3,
Make sure your view controller complies with the following:
UICollectionViewDelegate,
UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout
Swift 3
If you are using swift 3, use this method:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
}
Notice the changes:
add _ before collectionView in the method name
NSIndexPath changes to IndexPath
I have the same requirement, in my case below solution is worked. I set UIImageView top, left, bottom and right constraints to 0 inside UICollectionviewCell
#IBOutlet weak var imagesCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// flowlayout
let screenWidth = UIScreen.main.bounds.width
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 10, right: 0)
layout.itemSize = CGSize(width: screenWidth/3 - 5, height: screenWidth/3 - 5)
layout.minimumInteritemSpacing = 5
layout.minimumLineSpacing = 5
imagesCollectionView.collectionViewLayout = layout
}
For my case, I wanted to show two columns and 3 rows in the UICollectionView
I added UICollectionViewDelegateFlowLayout delegate to my class
then I override sizeForItemAt indexPath
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellHeight = (collectionView.bounds.size.height - 30) / 3 // 3 count of rows to show
let cellWidth = (collectionView.bounds.size.width - 20) / 2 // 2 count of colomn to show
return CGSize(width: CGFloat(cellWidth), height: CGFloat(cellHeight))
}
The 30 is the Line spacing, the 20 is the insent between cells
Programatically set the itemSize to [UIScreen mainScreen].bounds.size.width/3
In my case, assuming every cell has a width of 155 and a height of 220. If I want to show 2 cells per row in a portrait mode and 3 for landscape.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
var itemsCount : CGFloat = 2.0
if UIApplication.sharedApplication().statusBarOrientation != UIInterfaceOrientation.Portrait {
itemsCount = 3.0
}
return CGSize(width: self.view.frame.width/itemsCount - 20, height: 220/155 * (self.view.frame.width/itemsCount - 20));
}
The best solution is to change the itemSize of your UICollectionViewFlowLayout in viewDidLayoutSubviews. That is where you can get the most accurate size of the UICollectionView. You don't need to call invalidate on your layout, that will be done for you already.
For my case, autolayout was only allowing the cell to grow to its content size even though I overrode the cell size in the storyboard, conformed to UICollectionViewDelegateFlowLayout, and implemented sizeForItemAt. So I made a dummy UIView the width of the cell's bounds.
UICollectionViewController:
extension CollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.bounds.width - 40
return CGSize(width: width, height: collectionView.bounds.height / 3)
}
}
Cell (I'm calling this method on dependency injection):
private func updateViews() {
let padding:CGFloat = 8
let innerView = UIView()
innerView.translatesAutoresizingMaskIntoConstraints = false
innerView.layer.cornerRadius = 8
innerView.layer.borderColor = UIColor.black.cgColor
innerView.layer.borderWidth = 1
contentView.addSubview(innerView)
NSLayoutConstraint.activate([
innerView.widthAnchor.constraint(equalToConstant: bounds.width - padding*2),
innerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: padding),
innerView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -padding),
innerView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: padding),
innerView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -padding)
])
}

Resources