Animating the UICollectionView Footer height - ios

I'm currently changing the height of my footer from the UICollectionViewDelegateFlowLayout:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
if shouldDisplay(){
return CGSize(width: UIScreen.main.bounds.width, height: 100)
}else{
return CGSize(width: UIScreen.main.bounds.width, height: 0)
}
}
But this doesn't provide the best user experience. I want to animate the height and provide a smooth (dis)appearance.
Unfortunately, I did not find any resources on this.

You should subclass UICollectionViewFlowLayout and implement initialLayoutAttributesForAppearingSupplementaryElement, finalLayoutAttributesForDisappearingSupplementaryElement functions.
You can get more information about custom layouts here

Related

UICollectionViewCell width is bigger than what I set in sizeForItemAt

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()
}

How to know collection view's `referenceSizeForHeaderInSection` method call has finished?

I have a viewController with a UICollectionView, to which I'm setting headers I need their height to be calculated dynamically. My implementation of the collectionView(_:layout:referenceSizeForHeaderInSection:) is similar to this:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
let width = collectionView.frame.size.width
customHeader.layoutIfNeeded()
let height = customHeader.container.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
return CGSize(width: width, height: height)
}
I'd need to know when this call has been completed and the size of the headers have been set, in order to trigger some other actions I need to perform.
I've seen that both viewDidLoad() and viewDidLayoutSubviews() methods of the viewController are called before this other one. Is there any way to achieve what I need?

Disable the other collection view from using the method sizeForItemAt

I have 2 collection views, one collection view is using sizeForItemAt for changing the size of the cell and other collection view should not be using that method.
My problem is how to disable/prevent the other collection view from using sizeForItemAt method.
If you are aiming to recognize the which collection view to be affected by sizeForItemAt method, you could simply use the === operator for doing it.
Example:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView === firstCollectionView {
// here it should returns the desired size
return CGSize(width: ..., height: ...)
}
// here it should returns the default size
return CGSize(width: ..., height: ...)
}
Or (a a shorter version):
return collectionView === firstCollectionView ? CGSize(width: ..., height: ...) : CGSize(width: ..., height: ...)
Put below code in your Cell size method
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//return CGSize.init(width: self.view.frame.width / 3 - 30, height: self.view.frame.width / 3 - 30)
if collectionView == myfirstCollectionview
{
//For FirstCollectionView
return CGSize.init(width: 90, height: 90)
}
else
{
//For SeondCollectionView
return CGSize.init(width: 90, height: 90)
}
}

How Can I resize collectionView header with referenceSizeForHeaderInSection?

I have a one section header and one UITextView in there, constraints 0 to all sides as Superview. Also I have a flow layout. I want to resize my header size after I filled my header reusable view using viewForSupplementaryElementOfKind.
How Can I reach my UITextView() in 0 section header. And than calculate my textView height to return exact value in this function.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: 200.0)
}
If someone explain this case, It would be great.
I was having a similar issue and finally tracked this down:
Make a UICollectionViewDelegateFlowLayout and then implement collectionView(_:layout:referenceSizeForHeaderInSection:)
So for example:
class ViewController: UIViewController,UICollectionViewDelegateFlowLayout {
...
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if section == 0 {
return CGSize.zero
}else{
//...
}
return CGSize(width: collectionView.frame.width, height: 60)
}

Adaptive UICollectionView Cell Width

I am new to collection view and Auto Layout and I have a problem making the cell sizes adapt to the various devices in the simulator. I am using the flow-layout and I set the sizes in the size inspector. The image I've provided shows the way I need the cells to look(canvas on the left iPhone5)on all devices. The iPhone4 display is good but the 6s is incorrect.
Can someone please show me how this is done as I cannot find the precise information I am looking for.
Thanks
Also, I'm not sure why the iPhone5 doesn't display the cells on the preview section like the 4&6 do..? any clues..?
screen shot1
With UICollectionView, you need to calculate the size of your cells, and the space around them (insets and interitem spacing) using delegate methods.
Something like this should work for you:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 8, left: 4, bottom: 0, right: 4)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return CGFloat(8)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let cellWidth = (view.bounds.size.width - 16) / 2
let cellHeight = cellWidth * 0.8 // multiply by some factor to make cell rectangular not square
return CGSize(width: cellWidth, height: cellHeight)
}
Within a UICollectionViewCell is where you would use Auto Layout to position the things in the cell, like labels, images, etc.

Resources