I would like to change the height of the header of my CollectionViewController.
I already know that I could use a code like that:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.size.width, height: 250)
}
I would like to do that, but directly within the UICollectionReusableView (the header view).
Is there any function that allows that?
You'll need to add UICollectionViewDelegateFlowLayout.
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
}
}
To change header size dynamically, use headerReferenceSize UICollectionViewFlowLayout property.
let collectionViewLayout = UICollectionViewFlowLayout()
collectionViewLayout.headerReferenceSize = CGSize(width: view.frame.size.width, height: 80)
Make sure not to include referenceSizeForHeaderInSection delegate method to make it work.
Headers in collectionview are diferent like tableview because you need to create diferent kind of cell, this cell is named UICollectionReusableView, create a class with this name and then in your collectionview check this option:
enter image description here
and then you can call this on code with this function:
override func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath) -> UICollectionReusableView {
//1
switch kind {
//2
case UICollectionElementKindSectionHeader:
//3
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind,
withReuseIdentifier: "UICollectionReusableViewID",
for: indexPath) as! UICollectionReusableViewClass
//Customize
return headerView
default:
//4
assert(false, "Unexpected element kind")
}
}
all the credits RayWenderLich tutorials : https://www.raywenderlich.com/1404-uicollectionview-tutorial-reusable-views-selection-and-reordering
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
Using UICollectionView with custom headers. Strange thing happening is custom cells hiding behind header cell. Below is code:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let reusableview = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "CalendarHeaderView", for: indexPath) as! CalendarHeaderView
switch kind {
case UICollectionView.elementKindSectionHeader:
reusableview.frame = CGRect(x: 0 , y: 0, width: self.view.frame.width, height: 40)
//do other header related calls or settups
reusableview.headerLabel.text = "Month"
return reusableview
default: fatalError("Unexpected element kind")
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.bounds.width / 7.0
let height = width
return CGSize(width: width, height: height)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionView.elementKindSectionHeader:
/// PROBLEM
reusableview.frame = CGRect(x: 0 , y: 0, width: self.view.frame.width, height: 40)
return reusableview
default: fatalError("Unexpected element kind")
}
}
You are not supposed to set the frame of UICollectionView.elementKindSectionHeader. UICollectionView does all of that for you. You just need to tell it how big (CGSize) it needs to be.
You can tell UICollectionView about this size via following method -
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: 40)
}
}
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 am trying to create UICollectionView Horizontal scrolling (like a top menu single row) with cell label. Here, I need to implement my label content different length so based on different length cell label should auto adjust Its width. I am using storyboard for my design.
Below my code
extension CameraViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Constants.reuseID, for: indexPath) as! cameraModeCollectionViewCell
cell.cameraMode.text = self.items[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 40, 0, 40)
}
}
Current output Iam getting
Implement UICollectionViewDelegateFlowLayout's method collectionView(_:layout:sizeForItemAt) and calculate the width of collectionViewCell based the width of text that you're populating the label with.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = self.items[indexPath.row]
let cellWidth = text.size(withAttributes:[.font: UIFont.systemFont(ofSize: 14.0)]).width + 10.0
return CGSize(width: cellWidth, height: collectionView.bounds.height)
}
In the above code I've used self.items[indexPath.row] as the source of text. 10.0 is the extra padding added to the cell.
In case the items array is optional, do unwrap the value of self.items[indexPath.row] before using.
Step 1 : Find the width of the text that has to be placed in each cell. This can be found using below function
string.size(withAttributes:[.font: UIFont.systemFont(ofSize: 14.0)]).width
Using this function we can find width of dynamic text during run time.
Step 2: Set the size of each cell using the width that we found in Step 1. Size of each cell is set using below delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
Combining Step 1 and 2, we can get a collection view which has cell width as per text width that is placed inside it.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = self.items[indexPath.row] // getting text of each index
let cellWidth = text.size(withAttributes:[.font: UIFont.systemFont(ofSize: 14.0)]).width + 10.0 // getting width of each text + extra margin of 10
return CGSize(width: cellWidth, height: 40.0) // height as per your requirement
}
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: