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:
- Override standard flow layout.
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:
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):
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
Related Topics
Symbolicate Crash in iOS8 with Xcode 6 .1
Where Is the Official Documentation for Cvopenglestexture Method Types
Removing Object from Array in Swift 3
Info.Plist Utility Error: "Info.Plist Couldn't Be Opened Because There Is No Such File"
How to Debug an Issue with a Release Mode Build in iOS
How to Get the MAC Os X Firewall to Permanently Allow My iOS App
How Do Set a Width and Height of an Image in Swift
How to Implement Localization in Swift Ui
Less Blur with 'Visual Effect View with Blur'
What Is Container View in iOS 5 Sdk
iOS Enterprise Provisioning Profile Expiration
Becomefirstresponder Not Working in iOS 8
New Itunes User Interface Unable to Find "Ready to Upload Binary"
In Os X 10.10 (Yosemite Beta), How to Test Using iOS 6.1 Simulator