Collection view spacing breaks the ui - ios

I'm trying to create an UI like below.
For this purpose I'm using UICollectionView and FlowLayout.
For showing the first cell with full width and remaining cell as 3 column, I've implemented the sizeForItemAtIndexPath: and minimumInteritemSpacingForSectionAtIndex methods:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
var cellSize = CGSizeZero
if indexPath.item == 0
{
let width = self.cvMedia.frame.width - 20
let height = (width * 9)/16
cellSize = CGSize(width: width, height: height)
}
else
{
let width = self.cvMedia.frame.width / 3 - 20
let height = (width * 16)/9
cellSize = CGSize(width: width, height: height)
}
return cellSize
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 20.0
}
But I'm getting the following output in iPhone 6SPlus and iPhone 6Plus:
I tried by changing the item spacing from 20 to 19 and it worked on simulator, but on actual device it still shows the same behaviour. If I change the spacing values I'm getting the correct output on some device versions, and not working on some versions. I can add a device version check and based on that I can return the value. But it is not an elegant solution and it will break on future versions. Can anyone help me to solve this issue ? Thanks in advance.

You should use the collection view's width as your parameter when making this layout.
For instance,
You need 3 cells to fit the view.
The cells must have 20pt spacing in between them.
Solution:
Calculate the size of the cell at runtime either on viewWillAppear() or cellForRowAtIndexPath()
Scenario:
Width of device is 320pt. Collectionview's width is 300pt( spacing 10pt L & R) Spacing : 20pt between cells. Cell's needed 3!!
Cell Size: ?
Now..Start calculating in either method.
Cell Spacing = (3-1) * 20 = 2 * 20 = 40pt
Remaining collection view width = 300pt - 40pt = 260pt
Cell size = 260pt/3 = 86.667 pt. (86pt apprx).
In Code:
cellWidth = ( collectionView?.bounds.width - minimumSpacing * (numberOfCellsInARow - 1 ) ) / numberOfCellsInARow
Also, this only gives the cellWidth. You need cellHeight as well.
You might already have an aspect ratio for the cell. Using that, calculate the cellHeight as well.
Kind Regards,
Suman Adhikari

Check out this and change the values for min spacing to 0 for both cells and lines

Related

UICollectionView challenge: set height on the last cell to fit availabe space

Can you solve the following problem: I have a UICollectionView with a fixed number of CollectionView Cells - but the hight of the devices change and I have to dynamically calculate the last(buttom) cell.
------
I: Cell 1
------
I: Cell 2
------
I: Cell 3, This cell has a dynamic hight
I
------
I have tried the following:
note: let view = self.cells[indexPath.row] is a fixed list of UIView that I add to the UICollectionView contextView in cellForItemAt
Also the code is in a class that implement UICollectionViewDelegateFlowLayout
self.collectionView?.isScrollEnabled = false
var totalHight: CGFloat = 0
public func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let view = self.cells[indexPath.row]
self.totalHight = self.totalHight + view.frame.size.height
if (self.totalHight > self.frame.size.height){
let diff = self.totalHight - self.frame.size.height
let height = (view.frame.size.height - diff)
view.frame.size = CGSize(width: self.frame.size.width,
height: height)
self.totalHight = 0
return view.frame.size
}else{
return CGSize(width: self.frame.size.width, height: view.frame.size.height)
}
}
I can't tell if that code you've tried is in your view controller or a custom layout. What was the result?
This can be done with a custom UICollectionViewLayout instance. You can probably get by with subclassing UICollectionViewFlowLayout and overriding
collectionView:layout:sizeForItemAtIndexPath:
Then you can look at the remaining space on the screen. It will probably pose problems if the content ends up exceeding the available space.
One approach you might look at is getting the layout attributes for the previous cell, and that will give you its frame, something like this:
let previousIndexPath = IndexPath(row: indexPath.row - 1, section: indexPath.section)
let attribs = layoutAttributesForItem(at: previousIndexPath)
let previousFrame = attribs.frame
let availableHeight = totalHeight - previousFrame.size.height
return CGSize(width: previousFrame.width, height: availableHeight)
See more here:
https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html
https://developer.apple.com/documentation/uikit/uicollectionviewlayout/1617797-layoutattributesforitem
Edit: as an aside, it sounds like maybe using UIStackView and autolayout constraints would make this thing much easier, since your content is static and doesn't scroll.

Swift 3 CollectionView scaling

I recently implemented a collection view in a app, the only problem I'm experiencing is that the collection view goes from 2 column to 1 column on smaller devices with a lot of padding on both sides
heres on a display smaller then a iPhone 6:
and heres how it looks on a display bigger or equal to a iPhone 6:
I did try several method where if the display width was smaller then a certain number it would scale up the cells, but it failed to work out because the cells where indeed scaled up but where not centered and over-lapping themselves.
You need to calculate the cell width.Try this code.
class YourClass: UIViewController {
//MARK:-Outlets
#IBOutlet weak var yourCollectionView: UICollectionView!
//Mark:-Variables
var cellWidth:CGFloat = 0
var cellHeight:CGFloat = 0
var spacing:CGFloat = 12
var numberOfColumn:CGFloat = 2
//MARK:-LifeCycle
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
yourCollectionView.contentInset = UIEdgeInsets(top: spacing, left: spacing, bottom: spacing, right: spacing)
if let flowLayout = yourCollectionView.collectionViewLayout as? UICollectionViewFlowLayout{
cellWidth = (yourCollectionView.frame.width - (numberOfColumn + 1)*spacing)/numberOfColumn
cellHeight = cellWidth //yourCellHeight = cellWidth if u want square cell
flowLayout.minimumLineSpacing = spacing
flowLayout.minimumInteritemSpacing = spacing
}
}
extension YourClass:UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: cellWidth, height: cellHeight)
}
}
You need to calculate your sizes depending on the phone size - if two cell's width are larger then screen size ( including all offsets between them ) they will layout as in the first picture.
You have two options:
One is to deal with sizes and rescale cells according to device size
Two leave it as is - Make small changes for iphone6/6s/7.
If you opt out for first one, you will need to set up constraint for these sizes - aspect ratio or center horizontally ( which could crop the image a little ).
For changing sizes dynamically, take a look at:
https://developer.apple.com/reference/uikit/uicollectionviewdelegateflowlayout
More specific:
https://developer.apple.com/reference/uikit/uicollectionviewdelegateflowlayout/1617708-collectionview

how to maintain spacing between uicollectionview cell

In my app I am using using UICollectionView. I want to set fix space between UICollectionViewCell. so how can I do this?
here is my code:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 20
}
by this line I can set space between cell?
here is my screenshot please see this. and let me know how can i set fix distance in both landscape or portrait mode
Maybe,you need implementation follow method.
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
You can adjust the spacing between UICollectionCell by using the storyboard Min. spacing property of UICollectionView.
Here you have to set Min spacing value for cells and lines.
Hope it would help you.
You can also manage the spacing using the size inspector of Collection View
http://i.stack.imgur.com/Nvp3g.png
If you want exact spacing between the cells you need to calculate the size for the cells that will best fit to allow for the spacing you need without wrapping while considering the sectionInsets and CollectionView bounds. eg.
let desiredSpacing: CGFloat = 20.0
if let layout = self.collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
layout.minimumLineSpacing = desiredSpacing
let totalCellsContentWidth = self.collectionView!.bounds.width - layout.sectionInset.left - layout.sectionInset.right
let numberOfCellsPerRow: CGFloat = 10
let numberOfSpacesPerRow = numberOfCellsPerRow - 1
let cellWidth = (totalCellsContentWidth - (numberOfSpacesPerRow * desiredSpacing) / numberOfCellsPerRow)
layout.itemSize = CGSize(width: cellWidth, height: cellWidth)
}
Assuming your cells are the same size the minimumLineSpacing is simple but would otherwise expand to fit the largest cell on the row before wrapping to the next line. As you can see it's the cell spacing that is a bit more complicated.

Custom layout UICollectionView swift

I am trying to achieve a custom layout like this one :
I am trying to implement it via a UICollectionView. First I use this code to have the desired size :
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
return CGSizeMake((collectionView.frame.size.width / 2) - 2 , (collectionView.frame.size.height / 3) - 2)
}
It's working fine.
The problem is that my picture is not properly centered. I did it this way :
Let me explain :
One constraint to align the center of the uiimage on X
One constraint to do the same thing on Y
One constraint to keep the image ratio
One constrain to say that the height of the image is 70% of the cell height
And the result is very not the one expected :
i did it using custom layout.
let collLayout:UICollectionViewFlowLayout = layout as! UICollectionViewFlowLayout
collLayout.scrollDirection = .Vertical
collLayout.minimumInteritemSpacing = 10
let width = (frame.size.width - 3*collLayout.minimumInteritemSpacing)*0.5
collLayout.itemSize = CGSizeMake(width, width)
collLayout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10)
And then initialize your collection view with this custom layout.

self-sizing collection view cells using swift not working

I'm trying to create a collection view with cells that can autosize. previously i had used sizeForItemAtIndexPath but could not get the cell height exactly right for a textView with attributedString. I've decided to abandon that approach and use the auto-sizing feature. I have found some information here but mostly with objective-C. I am only familiar with Swift. Even so, I have picked through it and it is still not working.
What I have done so far is to include the following code in my viewDidLoad:
if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = CGSize(
width: self.view.frame.size.width, height: 100)
}
the cell width is showing correctly however all the cell heights are stuck at 100 regardless of the content.
Is there something else I need to do to allow the autosizing to kick in? I'm pretty sure my storyboard constraints are set up correctly.
In addition to setting the estimatedItemSize, you should also make sure that you are not providing an item size via a delegate or datasource method. The point of the self-sizing mechanism is that UIKit will use the estimated item size as its initial estimate, and then calculate the exact height based on the Auto Layout constraints you've configured on the cell's contentView. Also, you need a Base SDK of iOS 8 or later.
This repo reproduces Apple's example from the WWDC session where they introduced self-sizing cells.
One workaround might be to size the collectionView cells height and width in proportion to the screen size:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let deviceSize = UIScreen.mainScreen().bounds.size
//let cellSize = sqrt(Double(deviceSize.width * deviceSize.height) / (Double(33)))
let cellWidth = ((deviceSize.width / 2) - 10)
let cellHeight = (deviceSize.height / 4)
return CGSize(width: cellWidth , height: cellHeight)
}

Resources