How Can I resize collectionView header with referenceSizeForHeaderInSection? - ios

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

Related

How to create dynamic width and static height for UICollectionView using Swift

I am implementing UICollection view with customcell. Here, I need to create dynamic width based on customcell label string and static Height need to set. Here, I used below code for dynamic width don’t know about static height. How to achieve this?
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return (items[indexPath.row] as String).size(withAttributes: nil)
//return CGSize(width: label.frame.width, height: 33.5)
}
}
Calculate the collectionViewCell's width based on the text that you want to add in the label.
Assuming that items is an array of String,
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let textWidth = items[indexPath.row].size(withAttributes:[.font: UIFont.systemFont(ofSize: 20.0)]).width + 30.0 //30.0 is the extra padding
let width = min(textWidth, 100.0) //100.0 is the max width
return CGSize(width: width, height: collectionView.bounds.height)
}
}
Add the attributes and the height as per your requirement.

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

Displaying two cells per row in CollectionView Swift

I am trying to set my collection view cell sizes so that I get two cells per row.
I have looked at plenty of solution for sizing cells for collection views. I actually have used some solutions before for sizing three cells per row that have worked for me.
What I have so far:
extension BusinessViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (view.frame.width - 20) / 2.0
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
Right now I just get one big cell per row and I don't know why. Usually when I have to have 3 cells per row, simply subtracting the insets from the views width and dividing by the number of desired cells is enough. Not sure why this is causing me an issue.
You can try checking the "estimatesSize" property of UICollectionView.
It could have been set to "Automatic" instead of "None".
I solved the same problem with this solution

Animating the UICollectionView Footer height

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

How to autolayout ImageView inside CollectionView so that cell to edge has same spacing as inner cells spacing?

I created UIImageView inside CollectionViewCell. I wanted for the layout to have the same spacing between the left most cell to left edge as spacing between inner cell, and same spacing for right most cell to the right edge of the screen. The current layout I have is like this:
In the image above the left edge to left most cell has 10 points spacing while the inner cells spacing is twice of that. That is because I have the UIImageView with 10points smaller in all 4 directions (up,down,left,right) against the CollectionViewCell.
I have spend significant time on this issue including searching StackOverflow but can't seems to find the answer.
I have no issue to create N number of cells in a row as per this posting and I've also played with the cell spacing as per this posting
I managed to find the solution to the above problem.
I did the following:
Remove all inner spacing between UIImageView and the CollectionViewCell. Then remove any offset and make the size match. Put constraint of 0 on all 4 directions.
Use the second reference mentioned above as template. I updated my ViewController with following contents:
extension ToDoCategoryViewController: UICollectionViewDelegateFlowLayout {
fileprivate var sectionInsets: UIEdgeInsets {
return UIEdgeInsetsMake(0, Constant.hardCodedPadding, 0, Constant.hardCodedPadding)
}
fileprivate var innerSpacing: CGFloat { return Constant.hardCodedPadding }
fileprivate var rowSpacing: CGFloat { return Constant.hardCodedPadding }
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var itemPerRow: CGFloat {
switch collectionView.bounds.width {
case 300..<500:
return 3
case 500..<800:
return 4
default:
return 5
}
}
let innerSpacingCount = itemPerRow - 1
let edgesPadding = Constant.hardCodedPadding * 2.0
let itemWidth = (collectionView.bounds.width - (innerSpacing * innerSpacingCount + edgesPadding)) / itemPerRow
let itemHeight = itemWidth * CGFloat(1.25)
return CGSize(width: itemWidth, height: itemHeight)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return rowSpacing
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return innerSpacing
}
}
In my code elsewhere, I set the Constant.hardcodedPadding value, e.g. CGFloat(30.0)
Thus, I get the following view:

Resources