I need to create a collectionView to display a series of images, individually for each photo. I'm trying to reproduce what you see in the picture, view a photo and then scroll left or right for the next. I can not create the layout of the collectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.datasource.count
}
//UICollectionViewDelegateFlowLayout - constraint della collecion view da innestare
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (UIScreen.main.bounds.size.width - 3) / 3
let height = width
return CGSize(width: width, height: height)
}
swift 4:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//calculation of cell size
return CGSize(width: self.collectionview.frame.size.width,height: 180)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
// indentation
return UIEdgeInsetsMake(0, 23, 20, 20)
}
If you want to drag to horizontal or vertical, in collectionview there is a "scroll Direction" attribute. You can change it to horizontal or vertical.
Related
I have a problem with UICollectionViewCell.
My UICollectionViewCell's width = UIScreen.main.bounds.size.width and it works fine before I add UILabel into the cell with constraints for left and right edges. If I add only for left it's ok. but when for both I have an issue.
Bug state :
Normal state:
extension YourViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 50)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return .zero
}
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 0
}
}
You can try this code.
In storyboard -> UICollectionView -> Change Estimate size as None in Size Inspector
you can set right constrain with greater than equal to constrain, so it can adjust appropriately.
Dont add a right constrain to the uicollection cell.
Simply provide a top and left (leading) constraint and the drag the uilabel to your desired width and then set a width constraint.
That should be all you need to get your desired outcome.
I am trying to create 2x2 grid layout using collection view.
I have used below code. It's kind of working fine for iPhone 5 but with tweaks. I am trying to write code that can be used on all screen sizes. This is not working on iPhone 6.
public func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
if let cell1 = cell as? CollectionViewCell {
return cell1
}
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 20
let collectionViewSize = collectionView.frame.size.width - padding
return CGSize(width: collectionViewSize/2, height: collectionViewSize/2+15)
}
public func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int
) -> UIEdgeInsets {
return UIEdgeInsets(
top: 5, left: 5, bottom: 5, right: 5
)
}
public func collectionView(
_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
I am trying to achieve following layout:
In future this grid can be like 2 columns only and N rows. Each row will always have 2 items.
First of all, get three variables together depending on your needs. Those are the minimum spacing (Both InteritemSpacing and Line spacing - Should be same UXwise but you can change that in delegate methods if you like. The interitem space however must always be equal to minimumSpacing), edgeInsetPadding and the number of items you want in a row.
private var numberOfItemsInRow = 2
private var minimumSpacing = 5
private var edgeInsetPadding = 10
In your code, you have already defined your Edge Insets as:
UIEdgeInsets(
top: 5, left: 5, bottom: 5, right: 5
)
The left and right insets are important for correctly determining the size of the item. left+right gives us a grand sum of 10. This should be assigned to edgeInsetPadding like this:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let inset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
edgeInsetPadding = inset.left+inset.right
return inset
}
Now lets get to your UICollectionViewDelegateFlowLayout. Update the following methods.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return minimumSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return minimumSpacing
}
Now lets get to the main part. Modify your sizeForItemAt in UICollectionViewDelegateFlowLayout as:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (Int(UIScreen.main.bounds.size.width) - (numberOfItemsInRow - 1) * minimumSpacing - edgeInsetPadding) / numberOfItemsInRow
return CGSize(width: width, height: width)
}
And this is it. You now get two equal size tiles in 2x2 grid. If you want to change this in future, just change the numberOfItemsInRow variable to something else. Like 3 for 3x3.
This will be done using the item size of the collectionViewCell
collectionView.delegate = self
extension ViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding = 5
let width = (collectionView.frame.size.width - CGFloat(padding) * 2) / CGFloat(2)
let height = width / 200 * 110 // or what height you want to do
return CGSize(width: width, height: height)
}
}
Use:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 20
let size = self.view.frame.width - padding
return CGSize(width: size/2, height: size/2+15)
}
I'm making an app which contains a UITableView, and inside this UITableView, there is a cell containing a horizontal UICollectionView.
Into this UICollectionView, I'm trying to display only one item, and a part of an other, to indicate to the user that he can scroll to the right.
Here is the result I would like to get :
But actually, here is what I get :
Here is my code :
extension CollectionViewCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var width = self.frame.width - 32.0
return CGSize(width: width, height: 275.0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.zero
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
As you can see, the sizeForItem width is self.frame.width - 32.0 and not self.frame.width - 48.0. I did this because my collectionView cell contains a container, which has a right spacing of 16.0pt with its superview.
Anyone has the solution to get the right behavior ?
So I have these delegate methods that help me layout my collectionView. I am trying to create somewhat of a grid layout where there are X numberOfSections and X numberOfItemsInSection. Based off of what I have now it lays out all of the rights next to each other and spaces them out a little too far as to where cells go to the next line. How do I go about fitting all the cells for a section on one line.
//Asks the delegate for the size of the header view in the specified section.
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return .zero
}
//Asks the delegate for the size of the footer view in the specified section.
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return .zero
}
//Asks the delegate for the size of the specified item’s cell.
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (collectionView.bounds.size.width - CGFloat(numberOfItemsInSection))/2.2, height: collectionView.bounds.size.height - 50)
}
//Asks the delegate for the margins to apply to content in the specified section.
//in short in controls the amount of space between the items above,left,right, and below
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
}
//Asks the delegate for the spacing between successive rows or columns of a section.
//controls the space in between rows and columns
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
//Asks the delegate for the spacing between successive items of a single row or column.
//controls the space between each cell
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
I feel like it has to do with the sizeForItemAt but I can't exactly figure out how to change it.
This is what it currently looks like.
You're right, it has to do with sizeForItemAt method, you should use the indexPath parameter so you can use its property section to define the size for each item in each section.
Just remember that there is a space between items so you need to take that into account when calculating the width and height, so you can adjust the spacing using minimumLineSpacingForSectionAt and minimumInteritemSpacingForSectionAt methods.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if indexPath.section == 0 {
return CGSize(width: 200, height: 100)
}
return CGSize(width: (collectionView.bounds.size.width - CGFloat(numberOfItemsInSection))/2.2, height: collectionView.bounds.size.height - 50)
}
I have a UICollectionView with cells of equal size. I want to make the distances between cells and between the cells and the left and right of the collection view all equal, with 2 cells in each row.
The content of each cell is horizontally centered, so I've tried setting the width of the cells to half the collection view's width:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: eventCollectionView.frame.width/2, height: 111)
}
But this produces the following:
As seen, the two cells are at 1/4 and 3/4th of the width. Instead I want them to be at 1/3 and 2/3 so the space between them and the edges are all equal.
Does anybody know how I'd accomplish this?
use bellow code
fileprivate var defaultspacing: CGFloat = 5
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var size: CGSize = .zero
let width = (SCREEN_WIDTH - (3 * defaultspacing))/2
size = CGSize(width: width, height: width)
return size;
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(self.defaultspacing, self.defaultspacing, 0, self.defaultspacing);
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return self.defaultspacing;
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat
{
return self.defaultspacing;
}
For that, you have to set section Inset property from storyboard whatever you want from left and right side of the collection view, also set the Min Spacing property from storyboard you want
In my case, I want 5 px from both the side and 5 px between 2 cell.
and in delegate method write,
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (eventCollectionView.frame.width - 15)/2, height: 111)
}
Add following method in your class
You can make changes as per your needs
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: CGFloat(collectionView.frame.size.width / 2 -10), height: CGFloat(111)) // here 10 is the space of cells
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets{
return UIEdgeInsetsMake(2, 2, 2, 2)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10.0
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10.0
}
Pictures make a lot of sense. My solution will work in every devices in right format.
Why?
Please go through the solution.
Step 1:
My base layout is iphone 7 plus and i have calculated for this devices.Calculation is done because i need to support all devices.So i had make some constants like below:
var SCREEN_WIDTH = UIScreen.main.bounds.size.width
var SCREEN_HEIGHT = UIScreen.main.bounds.size.height
var BASE_SCREEN_HEIGHT:CGFloat = 736.0
var SCREEN_MAX_LENGTH = max(SCREEN_WIDTH, SCREEN_HEIGHT)
var ASPECT_RATIO_RESPECT_OF_7P = SCREEN_MAX_LENGTH / BASE_SCREEN_HEIGHT
let MINIMUM_INTERITEM_SPACING:CGFloat = 46 //My Default Inter Cell Spacing for iphone 7plus as i have designed in it.
var ITEM_WIDTH:CGFloat = 138 //for iPhone 7 plus.initial value
var ITEM_HEIGHT:CGFloat = 138 //for iphone 7 plus.initial value
let NUMBER_OF_CELLS_IN_PORTRAIT:CGFloat = 2
let NUMBER_OF_CELLS_IN_LANDSCAPE:CGFloat = 5
Step 2:
Then i had to calculate cellsize according the exact space between cells.
func calculateCellSize(screenWidth:CGFloat , cellItem:CGFloat) {
ITEM_WIDTH = (screenWidth - MINIMUM_INTERITEM_SPACING * 3 *
ASPECT_RATIO_RESPECT_OF_7P * (cellItem-1)) / cellItem - 1// This 1
has been subtracted from ITEM_WIDTH to remove mantissa
ITEM_HEIGHT = ITEM_WIDTH
}
Step 3:
For between cell spacing you need to call below method.
public func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return MINIMUM_INTERITEM_SPACING * ASPECT_RATIO_RESPECT_OF_7P
}
And for Padding(with left margin and right margin) you have to call this method.
public func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout, insetForSectionAt
section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0,
MINIMUM_INTERITEM_SPACINGASPECT_RATIO_RESPECT_OF_7P, 0,
MINIMUM_INTERITEM_SPACINGASPECT_RATIO_RESPECT_OF_7P)
}
Overall i had to call 4 methods.I didn't explain the other two methods may be you will understand.
So basically whole code is like this.
And my output is