I am creating a UICollectionView, but when a new cell is added to the view it is partially overlapping the previous cell. Below is my code:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
cell.frame.size.width = self.view.frame.width / 3
cell.frame.size.height = self.view.frame.height / 4
cell.backgroundView = imageView
return cell
}
How do I make sure the cells don't overlap?
You shouldn't assign the frame value by yourself in the cellForItemAtIndexPath method.
The more suitably way is to do this in the UICollectionViewLayout, then set it as the collectionview's layout property. Actually, you need a UICollectionViewLayout instance when you init the UICollectionView instance.
Or simply, use the UICollectionViewFlowLayout which system provides to implement the flow layout conveniently, tell it the size of each cell, spaces between them, and some other informations by its delegate. The layout instance will arrange all for you.
For example.
class MYViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
//In viewDidLoad()
var collectionViewFlowLayout = UICollectionViewFlowLayout()
var myCollectionView = UICollectionView(frame: self.view.bounds, layout: collectionViewFlowLayout)
// A flow layout works with the collection view’s delegate object to determine the size of items, headers, and footers in each section and grid.
// That delegate object must conform to the UICollectionViewDelegateFlowLayout protocol.
myCollectionView.delegate = self
myCollectionView.dataSource = self
// MARK: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(10, 10);
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 10;
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return 10;
}
}
For more infomation, read the doc.
For me it was the wrong cell width and height specified in the size inspector of the view controller. Just set that properly possibly the same as your nib file and it may work.
Please see screenshot for clarity.
All what you need is to extend you ViewController from UICollectionViewDelegateFlowLayout and implement sizeForItemAt :
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if (collectionView == myCollectionView_1) {
return CGSize(width: self.view.frame.width / 3, height: self.view.frame.height / 4)
} else {
return collectionView.frame.size
}
}
For me, simply changing Estimated Size to None at the collection view options fixed the problem.
For ref please check the below screenshot:
Related
I'm a beginner don't mind my coding nor my english I hope you can help me with this problem that you even might find it silly.
I have been facing a problem with resizing the cell.
I saw a few youtube tutorials and still couldn't find how to solve it!!
I changed the sizes here
I also tried and changed it in the cell (the book picture is actually a button)
and here is the output. so how can I resize it? I want it to be 2 columns
here is the code
class resViewViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 140, height: 180)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return resourcesName.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collection.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! resourceCellCollectionViewCell
cell.name.text = resourcesName[indexPath.row]
return cell
}
the new output after fixing the code
I think the class you are looking for is the UICollectionViewDelegateFlowLayout. Your UICollectionView has a delegate and the delegate can implement the UICollectionViewDelegateFlowLayout protocol. Inside that implementation you can specify the size of the cells by implementing
collectionView(_:layout:sizeForItemAt:)
So I would expect your code above to read:
class resViewViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 140, height: 180)
}
Note that the class is implements the UICollectionViewDelegateFlowLayout protocol instead of just UICollectionViewDelegate
Then, in your Layout, you need to set the autoresizing mask of the view contained in the cell so that it shrinks or grows with the cell itself
I am new to Swift and I am trying to create a UICollectionViewCell. It builds successfully but the cells are not the size that I thought I was creating. There are supposed to be two columns and and it is supposed to contain an image, description and price. I know it is something simple but I cannot figure out what I am doing wrong. See the image below. I assume I need to fix something in the size inspector but I cannot figure out what.
import UIKit
class ProductsVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
#IBOutlet weak var productsCollection: UICollectionView!
private(set) public var products = [Product]()
override func viewDidLoad() {
super.viewDidLoad()
productsCollection.dataSource = self
productsCollection.delegate = self
}
func initProducts(category: Category){
products = DataService.instance.getProducts(forCategoryTitle: category.title)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return products.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProductCell", for: indexPath) as? ProductCell {
let product = products[indexPath.row]
cell.updateViews(product: product)
return cell
}
return ProductCell()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height: CGFloat = 280
return CGSize(width: (collectionView.frame.size.width - 10) / 2, height: height)
//10 is minimum line spacing between two columns
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
FYI
Try this:
// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// You can change collection view cell height here, It's up to your design
let height: CGFloat = 150
let width: CGFloat = (collectionView.frame.size.width - 10 - a) / 2 // a is extra spacing of collection view (like leading or trailing constraints)
// Converting CGFloat to Int make sure the width of total cells are less than or equal the screen width
return CGSize(width: Int(width), height: Int(height)) // 10 is minimum line spacing between two columns
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
Please check extra spacings example with the below photo:
a = 20 with my example design (leading = 10, trailing = 10)
just provide the itemSize when you declare the collectionView:
let layout = UICollectionViewFlowLayout()
layout.itemSize = sizeForEachItem
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
I am trying to implement following screen.
But in my code, it is displaying following way
following code I wrote,
import UIKit
class LunchViewController: UIViewController {
#IBOutlet weak var mainCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
extension LunchViewController:UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 412, height: 180)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return self.myLibraryArray.count
return 8
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// let item = self.myLibraryArray[indexPath.row]
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RestaurantCollectionViewCell", for: indexPath) as? RestaurantCollectionViewCell else {
return UICollectionViewCell()
}
//cell.fillDetails(item)
return cell
}
}
Here is the complete project link
Can any one tell me, what is the issue? or what I have to write the code to get expected output?
Update:
Select collectionView and Change Estimate Size to none. In storyboard.
if you dont want space between two cells then set 0 to for lines in Min spacing
And i have given width as screen width
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: UIScreen.main.bounds.size.width, height: 180)
}
Output :-
Change sizeForItem method to this:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width, height: 180)
}
Also, make sure the mainCollectionView is constrained to the leading and trailing edges in the storyboard.
I have a chat app and the chat collectionView is created in a pod file that I don't have access to change. Each chat message is a section in the collectionView. I can determine the number of sections (chat messages) by calling myCollectionView.numberOfSections.
I want to determine the height of each section in the collectionView. How might I do this programmatically without using the collectionView protocol methods.
you can try this way:
class ThirdPartyViewController: UIViewController {
var collectionView: UICollectionView!
}
class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout {
let vc = ThirdPartyViewController()
var collectionView: UICollectionView { return vc.collectionView }
var originDelegate: UICollectionViewDelegateFlowLayout { return vc as! UICollectionViewDelegateFlowLayout }
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
//return custom value
return CGSize(width: 100, height: 100)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//return origin value
return originDelegate.collectionView!(collectionView, layout: collectionViewLayout, sizeForItemAt: indexPath)
}
}
I have one collectionview and a cell inside that which is having a fixed width and dynamic height based on its contents.I am using autolayout constraints , my code is below.
I have already tried to set all types of auto constraints inside the cell and inside the view .
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! ViewControllerCell
cell.lbl_text.text = "djs sdfs sdfs dsfsfd gdgfd dfgd df "
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if let flowLayout = coll_main?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
}
In cell class method:
override func awakeFromNib() {
super.awakeFromNib()
self.contentView.autoresizingMask = [UIView.AutoresizingMask.flexibleHeight]
}
override func layoutSubviews() {
self.layoutIfNeeded()
}
i get cell width fix without i am set that width. how may this issue solve?
here screenshots.
You need to make sure that your Estimate Size is set to None for your CollectionView.
Please do the following steps
Select your collectionView in interface builder.
Go to the size inspector
Change estimated size to none as shown in the image.
Hopefully it will fix the problem
You can use collectionView delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width:, height:)
}
for this you need to extend UICollectionViewDelegateFlowLayout
You have to use UICollectionViewDelegateFlowLayout and implement sizeForItemAt like following.
// MARK: - UICollectionViewDelegateFlowLayout -
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let sectionInset = (collectionViewLayout as! UICollectionViewFlowLayout).sectionInset
// Here you can set dynamic height for the individual cell according to your content size.
let referenceHeight: CGFloat = 100 // Approximate height of your cell
let referenceWidth = collectionView.safeAreaLayoutGuide.layoutFrame.width
- sectionInset.left
- sectionInset.right
- collectionView.contentInset.left
- collectionView.contentInset.right
return CGSize(width: referenceWidth, height: referenceHeight)
}
Here is an articale about it, you can follow this.
Add this property in your collection view or uncheck PrefetchingEnabled property in your nib.
collectionView.isPrefetchingEnabled = false
Implement UICollectionViewDelegateFlowLayout method for collection cell size.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
Then go to the storyboard and in size inspector make collectionView Estimate size to None