Disable supplementary view - ios

What is the correct of of disabling the supplementary views (e.g. header)? One time I want to show them (iPhone) and one time I don't want to show them (iPad).
The only idea I currently have is to return a size of zero in referenceSizeForHeaderInSection. But I think it's kind of an overhead to create views, which aren't used at all. On the other side I have to implement collectionView:viewForSupplementaryElementOfKind:atIndexPath: and I can't return nil, because the app crashes then.
How can I disable the supplementary views in UICollectionView?

If you return CGSizeZero from collectionView:layout:referenceSizeForHeaderInSection: delegate method collectionView:viewForSupplementaryElementOfKind:atIndexPath: won't be called.

Apple Developer API Reference states about collectionView(_:layout:referenceSizeForHeaderInSection:):
If the size in the appropriate scrolling dimension is 0, no header is added.
The following Swift 5 code snippet shows a possible implementation of collectionView(_:layout:referenceSizeForHeaderInSection:) in order to display or not UICollectionView supplementary views:
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad {
return CGSize.zero
} else {
return CGSize(width: 0, height: 40)
// or
//let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
//return flowLayout.headerReferenceSize
}
}

Related

Dynamic CollectionViewHeader Cell Sizing of a complex layout

I have read multiple answers on StackOverflow but nothing seemed to works or is used for my case.
I have a collectionview header that needs to be self sizing, but the header also contains views that can be hidden with a stackview or not depending on the data.
I don't know how I am suppose to get this to self sizing:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if(section == 0){
return CGSize(width: view.frame.width, height: 500)
}
return CGSize(width: view.frame.width, height: 100)
}
My header contains multiple views that changes height dynamically because of the stackview.
Is there a way that I could layout the header then get the height of a view inside the cell then readjust cell size?
first of all your section header is just a UICollectionViewCell or UICollectionView.elementKindSectionHeader ?
second I think this might help I have a smiler case in my project and it worked for me
https://www.vadimbulavin.com/collection-view-cells-self-sizing/

Custom cell width for one collectionView

I have 3 collectionViews in one view controller. One has all cells of the same width and does not change. The other I would like to set the cell width in code using a constant. The last will calculate its cell's width based on the previous constant and other factors in a custom flow layout.
I tried
extension YourViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == neededCollectionView {
return CGSize(width: constantWidth, height: constHeight)
} else {
// here ignore all the others and tell them to get this size as usual
}
}
}
but this seems to modify the width for all the collection views .. How do I get this two ignore the 2 collection views that have their size calculated somewhere else
in this function you can't ignore,
you need to return
CGSize
always.
try a break point and check if it gets into the else closure if so
you could try to add this line,
return CGSize(width: yourDefualtWidthConst, height:yourDefualtHeightconst)
or this
return collectionView.itemSize
You have Two options
FIRST OPTION : Return the estimatedItemSize of each CollectionViewCell
1. Get an IBOutlet Reference from each CollectionViewFlowLayout
#IBOutlet weak var firstFlowLayout: UICollectionViewFlowLayout!
2. Add UICollectionViewDelegateFlowLayout delegate in your viewController
3. Implement the delegate method
func collectionView( _ collectionView: UICollectionView,layoutcollectionViewLayout: UICollectionViewLayout,sizeForItemAtindexPath: IndexPath) -> CGSize {
if collectionView.tag == 1 {
return CGSize(width: constantWidth, height: constHeight)
} elseIf collectionView.tag == 2 {
return firstFlowLayout.estimatedItemSize
}
}
SECOND OPTION : Adepter Design pattern
You can also use adapter class for each collectionview and each adapter has a different implementation to resolve this like this
https://stackoverflow.com/a/50920915/5233180
NOT : This implementation for TableView you can make it for collectionview

Simply using storyboard, constraints to set size of cell in UICollectionView

Here's a UICollectionView, and the cell in purple:
Quite simply, I want the cells to be 1/2 of the collection view width. (So TBC, it will be a two rows arrangement of cells in the collection view.)
(The collection view is simply fullscreen, so each cell is half the screen width.)
How do you do this in storyboard?
If I try to control-drag in the normal way, it basically doesn't work.
These are simple totally static cells (not dynamic).
For anyone googling here, to save your time: Here's exactly (2016) the simplest way to make a two-across UICollectionView layout; no gaps between the cells.
// Two - two-across UICollectionView
// use a completely standard UIViewController on the storyboard,
// likely change scroll direction to vertical.
// name the cell identifier "cellTwo" on the storyboard
import UIKit
class Two:UICollectionViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
let w = collectionView!.bounds.width / 2.0
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width:w,height:w)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView!.collectionViewLayout = layout
// Note!! DO NOT!!! register if using a storyboard cell!!
// do NOT do this:
// self.collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
{ return 1 }
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{ return 5 }
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
return collectionView.dequeueReusableCellWithReuseIdentifier("cellTwo", forIndexPath: indexPath)
}
}
You can't do it in the storyboard. The collection view width is not known until runtime, and collection view cells are not under autolayout, so you cannot express the notion "1/2 the width" of anything else. (If you did know the collection view width in advance, you could use the flow layout in the storyboard to set the cell size absolutely, by dividing in your head; but you don't know it, because the width differs depending on the device.)

Dynamic Height for UICollectionView Cell

This is my first attempt at creating a collectionView programmatically. I used a couple tutorials to get where I am now which is a Facebook/LinkedIn-esque layout with a textView and imageView. They look great when there is an image but I have no idea how to make the cell dynamically smaller in height when there is no image. I know that I currently have a fixed height of 500 but it being my first attempt, I am not sure how to set it to dynamically adjust.
I've seen a lot of Obj-C examples but nothing (that I can understand) for Swift that I know how to implement.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if let textContent = dataSource.posts[indexPath.item].textContent {
let rect = NSString(string: textContent).boundingRectWithSize(CGSizeMake(view.frame.width, 1000), options: NSStringDrawingOptions.UsesFontLeading.union(NSStringDrawingOptions.UsesLineFragmentOrigin), attributes: [NSFontAttributeName:UIFont.systemFontOfSize(14)], context: nil)
return CGSizeMake(view.frame.width, rect.height + 370)
}
return CGSizeMake(view.frame.width, 500)
}
}
My vertical visual layout constraints (created with an extension):
addContstraintsWithFormat("V:|-8-[v0(44)]-4-[v1]-4-[v2][v3(44)][v4(1)][v5(44)]|", views: profileImg, postTextView, postImageView, likesCommentsLabel, dividerLineView, likeButton)
sizeForItemAtIndexPath is one of the collection view delegate function in which you can set the height of each cell. In this delegate just add a condition.. where you can check if the cell has an image or not and based on that set the height using CGSizeMake

How to configure a UICollectionView Cell Size per Size Class?

I'm finding friction when trying to create responsive / adaptive UICollectionViewCells in the UIStoryboard.
The issue I'm seeing is that you don't seem to be able to set the Cell Size per Size Class and I'm trying to ascertain the right approach to this. I've designed the cells to adjust to their containers, so that they should autosize regardless of size class. This mostly works in that if I change the size class, select my cell view and do Update Frames then they all resize to fit their new size. However it's a one shot deal, if I go back to the Any/Any size class then I'm still seeing that resized version.
Here's what I'm aware I could try:
Create multiple cells, with fixed dimensions, one per size class and in the Storyboard view. I could then only use the right one at runtime but I could then see them at design time.
I could create a collection view Per Size class, each one only being installed for that size. This would work, but would be a pain to manage the multiple UICollectionViews
Create my interface and/or constraints programmatically (losing visibility of the design).
I'm hoping this is a solved scenario and I'm just missing something, but I'm aware that it could be that the IB tools don't match the code at this point.
The solution I came up with was just to implement the UICollectionViewDelegateFlowLayout and implement the sizeForItemAtIndexPath method.
This means that the cell dimensions can be set to match the available Size Class dimensions.
This still isn't ideal as you can't see the changes in the storyboard and you can't create a universal design and see it in each of the different formats.
I'm still hoping someone has a better option.
Here's a similar solution coded-out in Swift. I just styled both of my cells in the storyboard and leave them viewable for any size class combination. When the trait collection changes I update the cellSize and cellReuseID I want to use and tell the collectionView to reload all the visible cells. Then
collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
and
override func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
(not shown in sample code) are called which lets me update the size of the cell and update the cell's storyboard styling. So not entirely done in storyboard, but good enough until more support is provided in Xcode.
struct MyCollectionViewConstants{
static let CELL_ANY_ANY_REUSE_ID = "cell";
static let CELL_COMPACT_REGULAR_REUSE_ID = "cellSmall"
static let CELL_ANY_ANY_SIZE = 100;
static let CELL_COMPACT_REGULAR_SIZE = 70;
}
class MyCollectionView: UICollectionViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var cellSize = MyCollectionViewConstants.CELL_ANY_ANY_SIZE
var cellReuseID = MyCollectionViewConstants.CELL_ANY_ANY_REUSE_ID
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
return CGSize(width: cellSize, height: cellSize)
}
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact
&& self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClass.Regular){
cellSize = MyCollectionViewConstants.CELL_COMPACT_REGULAR_SIZE
cellReuseID = MyCollectionViewConstants.CELL_COMPACT_REGULAR_REUSE_ID
} else {
cellSize = MyCollectionViewConstants.CELL_ANY_ANY_SIZE
cellReuseID = MyCollectionViewConstants.CELL_ANY_ANY_REUSE_ID
}
self.collectionView.reloadItemsAtIndexPaths(
self.collectionView.indexPathsForVisibleItems())
}
}
I was stuck with same problem after implementing size class(iPad and iPhone).Well, I figured out a solution. Hope it helps!
Implement UICollectionViewDelegateFlowLayout.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
var device = UIDevice.currentDevice().model
var cellSize:CGSize = CGSizeMake(155, 109)
if (device == "iPad" || device == "iPad Simulator") {
cellSize = CGSizeMake(240, 220)
}
return cellSize
}
Swift 4
Hi Fellow Developers,
This is easy to do if the height and width of the UICollectionViewCell are same.
Steps
1. Import ** UICollectionViewDelegateFlowLayout**
2. Add the sizeForItem IndexPath method of UICOllectionView as follows
func collectionView(_ collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAt indexPath:IndexPath) -> CGSize {
return CGSize(width: collectionVw.frame.size.height, height: collectionVw.frame.size.height)
}
Note: What happening is you are setting the height of the UICollectionView as height and width of the UICollectionViewCell
Happy Coding :)

Resources