I would like to have 3 small cell, then 2 big cells, and then 3 small cells again, repeatedly, in my UICollectionView,
I know that it has something to do with this function, but I am confused as how to achieve the result
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
}
Please take a look at the screenshot.
You can calculate modulo of indexPath.row like this way.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if (indexPath.row % 5 == 3 || indexPath.row % 5 == 4) {
//return big cell size
let size = (collectionView.frame.size.width - minSpace) / 2
return CGSize(width: size, height: size)
}
else {
//return small cell size
let size = (collectionView.frame.size.width - minSpace) / 3
return CGSize(width: size, height: size)
}
}
Note: Here minSpace is minimum space that you want between two cells.
Related
In my UICollectionView, the last cell indexPath is 10. I want the last cell to fill the width. Now there are 2 cells each line, but I want the last cell to fill the whole width. This is what I have tried;
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (view.frame.size.width - 40) / 2
if indexPath.item == 10 {
return CGSize(width: view.frame.size.width, height: CGFloat(100))
}
return CGSize(width: width, height: 100)
}
When I run the app and press the last cell, this output run:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
}
But somehow, this doesn't do anything. Any tips please?
Got it working by myself. I forgot to add the UICollectionViewDelegateFlowLayout.
Width/height of my UICollectionView matches all available space.
I want to display two cells in one row (two columns)
So width of one cell should take half width of UICollectionView (collectionView.frame.width / 2)
So I programmatically change width of cell in function of UICollectionViewDelegateFlowLayout:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width / 2.0, height: 150)
}
But visually width of cell is much bigger than collectionView.frame.width / 2.0 (tested on iPhone SE simulator)
So it takes more than half-width space of screen
Here I printed info about sizes:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
print("didSelectItemAt \(cell.frame.width), table width: \(collectionView.frame.width), item calc width: \(collectionView.frame.width / 2)")
}
didSelectItemAt cell width 187.5, table width: 375.0, half-width:
187.5
Why does it happen?
There is also an issue with margins but first I have to solve this one
Update
Though it works fine with iPhone 6s Simulator (I edited image to place two items in the first row to check if they fit):
So what is wrong with iPhone SE?
I don't want to find out that there can be the same issue with other iPhones or iPads too
375.0 is the size of iPhone 6s and X, not iPhone SE which is 320.0
The reason is there is a width constraint of collectionView which was set at iPhone 6s mode but later when switching to the SE simulator, this constraint was not updated.
I think there is problem of cell spacing. it seems there is default cell spacing exists in your implementation. you should try below code to adjust two cell in one raw of collectionview:
extension ViewController : 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 collectionViewWidth = collectionView.bounds.width
return CGSize(width: collectionViewWidth/2, height: 150)
}
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 0
}
}
moreover, you should check constraint of your UICollectionView if it is as per your requirement Or not.
Try to use the wide from the view, not the collectionView.
Try this:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (view.frame.width / 2.0) - 5, height: 150) // provide little bit space between cells
}
Hope this will help.
The best solution is, to reload your collection view in main thread with a bit delay.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.10) {
self.myCollectionView.reloadData()
}
I am trying to implement a collection view where I have to load images from the API data. Challenge here is that my collection view is a 2 column grid and if the number of images are odd, then the first cell should span to full row. Here is the design mock up I want
So as per the mockup
If items are even, then display them 2 in each row.
If items are odd, display the first one to span the full row, and show the remaining spanning 2
in each row.
I am following this tutorial to create grid view but don't know how to achieve the designs in mockup
https://www.raywenderlich.com/136159/uicollectionview-tutorial-getting-started
Any help would be appreciated. Thanks in advance.
You can just check the number of items that you have and set the sizes depending if is odd or not. If it is odd and you want only the first item in each three to be of bigger size you can also check for the remainder by dividing by 3. Here is the example.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView.numberOfItems(inSection: 0) % 2 == 0 {
return CGSize(width: (collectionView.frame.size.width - 5) / 2, height: (collectionView.frame.size.width - 5) / 2)
}
let remaider = (Double(indexPath.item)/3).truncatingRemainder(dividingBy: 1)
if remaider == 0 {
return CGSize(width: self.collectionView.frame.size.width, height: self.collectionView.frame.size.width)
}
return CGSize(width: (collectionView.frame.size.width - 5) / 2, height: (collectionView.frame.size.width - 5) / 2)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
I am Trying to resize my cell based on the screen size so that there is only 2 cell per row. I am using the code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: MyCollectionView.bounds.width / 2.2, height: MyCollectionView.bounds.height / 5.5)
}
This works and resizes to the different screen sizes. I run it on. however when you rotate into landscape mode it displays more than two cells per row.
If The container of MyCollectionView is self.view then plz give a try to this . .
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.view.frame.width / 2.2 , height: MyCollectionView.bounds.height / 5.5)
}
I have a UICollectionView that displays two kind of cells according to whether the item in its datasource is a "folder" or a "photo"
It appears that when the UICollectionView is populated with both type of cells and when there are less than 3 number of "photo" cells to show per row, the cells are not being left-aligned one next to each other but rather try to fill out the whole empty space of the row.
Preview 1:
Preview 2
However when the exact UITableViewCollection displays only "photos" cells, it seems to be behaving normally:
Here are the delegate methods that handle the cell sizes and spacing:
extension DropboxBrowserViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
{
let folderTypeCellHeight = CGFloat(64.0)
let collectionViewWidth = collectionView.bounds.size.width
let numOfPhotosPerRow = CGFloat(3.0)
let layout = collectionViewLayout as! UICollectionViewFlowLayout
let insets = (layout.sectionInset.left, layout.sectionInset.right)
// Go full width if the cell displayed a folder name
if let _ = listingsDataSource?.listings[indexPath.row] as? Files.FolderMetadata {
return CGSize(width: collectionViewWidth, height: folderTypeCellHeight)
}
// return size to fit `numOfPhotos` photos per row
else {
let cellSpacing = SavePhotosCollectionViewCell.cellSpacing
let cellSize = (collectionViewWidth - insets.0 - insets.1 - (CGFloat((numOfPhotosPerRow - 1)) * cellSpacing)) / numOfPhotosPerRow
return CGSize(width: cellSize, height: cellSize)
}
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
return 2.0
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0.0
}
Any ideas on why this might be happening?
Thanks
EDIT
The storyboard looks like this. I don't why the "photos" cell is being displayed in the middle over there and if this has something to do with the issue.