How to Change Space Between Cells in Uicollectionview

UICollectionView - distance between cells?

This UICollectionViewFlowLayoutDelegate method will help you..

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionView *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section  
{
return 10; // This is the minimum inter item spacing, can be more
}

One more if you need more space to arrange your cells adjust the edgeInsets also

Cell spacing in UICollectionView

I know that the topic is old, but in case anyone still needs correct answer here what you need:

  1. Override standard flow layout.
  2. Add implementation like that:

    - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *answer = [super layoutAttributesForElementsInRect:rect];

    for(int i = 1; i < [answer count]; ++i) {
    UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
    UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
    NSInteger maximumSpacing = 4;
    NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);

    if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
    CGRect frame = currentLayoutAttributes.frame;
    frame.origin.x = origin + maximumSpacing;
    currentLayoutAttributes.frame = frame;
    }
    }
    return answer;
    }

where maximumSpacing could be set to any value you prefer. This trick guarantees that the space between cells would be EXACTLY equal to maximumSpacing!!

How to set cell spacing and UICollectionView - UICollectionViewFlowLayout size ratio?

Add these 2 lines

layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0

So you have:

   // Do any additional setup after loading the view, typically from a nib.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 0, bottom: 10, right: 0)
layout.itemSize = CGSize(width: screenWidth/3, height: screenWidth/3)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView!.collectionViewLayout = layout

That will remove all the spaces and give you a grid layout:

Sample Image

If you want the first column to have a width equal to the screen width then add the following function:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if indexPath.row == 0
{
return CGSize(width: screenWidth, height: screenWidth/3)
}
return CGSize(width: screenWidth/3, height: screenWidth/3);

}

Grid layout will now look like (I've also added a blue background to first cell):
Sample Image

How to change space between cells in UICollectionView?

//Objective c
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake((collectionView.frame.size.width/3)-20, 100);
}

// Swift 2.0

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake((collectionView.frame.size.width / 3) - 20, 100)
}

// Swift 3.0
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: CGFloat((collectionView.frame.size.width / 3) - 20), height: CGFloat(100))
}

How do I change the horizontal spacing between cells in a horizontal scroll collection view

The answer is that in a horizontal scroll collection view, the distance between cells, even the horizontal distance, seems to be controlled by the For Lines parameter (in IB) or minimumLineSpacing parameter of the CollectionViewFlowLayout.

This answer is also buried in some answers I saw more general question about cell spacing in collection views:
https://stackoverflow.com/a/48791318/826946 and
https://stackoverflow.com/a/37420529/826946

I decided to separate it out into a separate question that directly addresses the issue of horitzontal scroll collection views.

Remove space between the cells of UICollectionView

From the comments, it is apparent that your FlowLayout methods are not being called.

Add UICollectionViewDelegateFlowLayout to your UICollectionView's class definition line.

Something like:

class MyCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

That will tell iOS that your class implements that protocol and supports the layout methods so that it knows to call them.

Remove spacing between each UICollectionViewCell and shift it to the outer cells of the UICollectionView

This can be achieved with a custom layout, subclassed from UICollectionViewFlowLayout. Here's an layout and demo CollectionView/Cell implementation.

Updated ViewController.swift

class ViewController: UIViewController {

private var collectionView: UICollectionView!
private let demoLabel = UILabel()
private let minCellSpacing: CGFloat = 16.0
private var maxCellWidth: CGFloat!

var data: [String] = ["Tech", "Design", "Humor", "Travel", "Music", "Writing", "Social Media", "Life", "Education", "Edtech", "Education Reform", "Photography", "Startup", "Poetry", "Women In Tech", "Female Founders", "Business", "Fiction", "Love", "Food", "Sports", "Autos", "Cleaning", "Technology", "Business", "Sports", "Childcare", "Airsoft", "Cycling", "Fitness", "Baseball", "Basketball", "Bird Watching", "Bodybuilding", "Camping", "Dowsing", "Driving", "Fishing", "Flying", "Flying Disc", "Foraging", "Freestyle Football", "Gardeing", "Geocaching", "Ghost hunting", "Grafitti", "Handball", "High-power rocketry", "Hooping", "Horseback riding", "Hunting"]

override func viewDidLoad() {
super.viewDidLoad()

self.maxCellWidth = UIScreen.main.bounds.width - (minCellSpacing * 2)

self.view.backgroundColor = .white
self.demoLabel.font = CollectionViewCell().label.font

let layout = FlowLayout()
layout.sectionInset = UIEdgeInsets(top: self.minCellSpacing, left: 2.0, bottom: self.minCellSpacing, right: 2.0)
layout.minimumInteritemSpacing = self.minCellSpacing
layout.minimumLineSpacing = 16.0

collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = .clear
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "cellId")
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: self.view.layoutMarginsGuide.topAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: self.view.layoutMarginsGuide.bottomAnchor).isActive = true

// Leading/Trailing gutter CellSpacing+ShadowWidth
collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: minCellSpacing + layout.sectionInset.left).isActive = true
collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -(minCellSpacing + layout.sectionInset.right)).isActive = true
}
}

extension ViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.data.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! CollectionViewCell
cell.label.text = self.data[indexPath.item]
return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
self.demoLabel.text = self.data[indexPath.item]
self.demoLabel.sizeToFit()
return CGSize(width: min(self.demoLabel.frame.width + 16, self.maxCellWidth), height: 36.0)
}

}

FlowLayout.swift

class FlowLayout: UICollectionViewFlowLayout {

private var attribs = [IndexPath: UICollectionViewLayoutAttributes]()

override func prepare() {
self.attribs.removeAll()
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var updatedAttributes = [UICollectionViewLayoutAttributes]()

let sections = self.collectionView?.numberOfSections ?? 0
var indexPath = IndexPath(item: 0, section: 0)
while (indexPath.section < sections) {
guard let items = self.collectionView?.numberOfItems(inSection: indexPath.section) else { continue }

while (indexPath.item < items) {
if let attributes = layoutAttributesForItem(at: indexPath), attributes.frame.intersects(rect) {
updatedAttributes.append(attributes)
}

let headerKind = UICollectionElementKindSectionHeader
if let headerAttributes = layoutAttributesForSupplementaryView(ofKind: headerKind, at: indexPath) {
updatedAttributes.append(headerAttributes)
}

let footerKind = UICollectionElementKindSectionFooter
if let footerAttributes = layoutAttributesForSupplementaryView(ofKind: footerKind, at: indexPath) {
updatedAttributes.append(footerAttributes)
}
indexPath.item += 1
}
indexPath = IndexPath(item: 0, section: indexPath.section + 1)
}

return updatedAttributes
}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
if let attributes = attribs[indexPath] {
return attributes
}

var rowCells = [UICollectionViewLayoutAttributes]()
var collectionViewWidth: CGFloat = 0
if let collectionView = collectionView {
collectionViewWidth = collectionView.bounds.width - collectionView.contentInset.left
- collectionView.contentInset.right
}

var rowTestFrame: CGRect = super.layoutAttributesForItem(at: indexPath)?.frame ?? .zero
rowTestFrame.origin.x = 0
rowTestFrame.size.width = collectionViewWidth

let totalRows = self.collectionView?.numberOfItems(inSection: indexPath.section) ?? 0

// From this item, work backwards to find the first item in the row
// Decrement the row index until a) we get to 0, b) we reach a previous row
var startIndex = indexPath.row
while true {
let lastIndex = startIndex - 1

if lastIndex < 0 {
break
}

let prevPath = IndexPath(row: lastIndex, section: indexPath.section)
let prevFrame: CGRect = super.layoutAttributesForItem(at: prevPath)?.frame ?? .zero

// If the item intersects the test frame, it's in the same row
if prevFrame.intersects(rowTestFrame) {
startIndex = lastIndex
} else {
// Found previous row, escape!
break
}
}

// Now, work back UP to find the last item in the row
// For each item in the row, add it's attributes to rowCells
var cellIndex = startIndex
while cellIndex < totalRows {
let cellPath = IndexPath(row: cellIndex, section: indexPath.section)

if let cellAttributes = super.layoutAttributesForItem(at: cellPath),
cellAttributes.frame.intersects(rowTestFrame),
let cellAttributesCopy = cellAttributes.copy() as? UICollectionViewLayoutAttributes {
rowCells.append(cellAttributesCopy)
cellIndex += 1
} else {
break
}
}

let flowDelegate = self.collectionView?.delegate as? UICollectionViewDelegateFlowLayout
let selector = #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:minimumInteritemSpacingForSectionAt:))
let delegateSupportsInteritemSpacing = flowDelegate?.responds(to: selector) ?? false

var interitemSpacing = minimumInteritemSpacing

// Check for minimumInteritemSpacingForSectionAtIndex support
if let collectionView = collectionView, delegateSupportsInteritemSpacing && rowCells.count > 0 {
interitemSpacing = flowDelegate?.collectionView?(collectionView,
layout: self,
minimumInteritemSpacingForSectionAt: indexPath.section) ?? 0
}

let aggregateInteritemSpacing = interitemSpacing * CGFloat(rowCells.count - 1)

var aggregateItemWidths: CGFloat = 0
for itemAttributes in rowCells {
aggregateItemWidths += itemAttributes.frame.width
}

let alignmentWidth = aggregateItemWidths + aggregateInteritemSpacing
let alignmentXOffset: CGFloat = (collectionViewWidth - alignmentWidth) / 2

var previousFrame: CGRect = .zero
for itemAttributes in rowCells {
var itemFrame = itemAttributes.frame

if previousFrame.equalTo(.zero) {
itemFrame.origin.x = alignmentXOffset
} else {
itemFrame.origin.x = previousFrame.maxX + interitemSpacing
}

itemAttributes.frame = itemFrame
previousFrame = itemFrame

attribs[itemAttributes.indexPath] = itemAttributes
}

return attribs[indexPath]
}
}

CollectionViewCell.swift

class CollectionViewCell: UICollectionViewCell {

let label = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)

self.label.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(label)
self.contentView.addConstraints([
NSLayoutConstraint(item: label, attribute: .leading, relatedBy: .equal, toItem: contentView,
attribute: .leading, multiplier: 1.0, constant: 8.0),
NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: contentView,
attribute: .top, multiplier: 1.0, constant: 8.0),
NSLayoutConstraint(item: contentView, attribute: .trailing, relatedBy: .equal, toItem: label,
attribute: .trailing, multiplier: 1.0, constant: 8.0),
NSLayoutConstraint(item: contentView, attribute: .bottom, relatedBy: .equal, toItem: label,
attribute: .bottom, multiplier: 1.0, constant: 8.0)])

self.backgroundColor = .white
self.label.textColor = UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 1)
self.layer.cornerRadius = 3.0
self.layer.shadowColor = UIColor.darkGray.cgColor
self.layer.shadowOffset = CGSize(width: 0.1, height: 0.2)
self.layer.shadowOpacity = 0.28
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Here is the final UI

Sample Image



Related Topics



Leave a reply



Submit