UICollectionView spacing margins
You can use the collectionView:layout:insetForSectionAtIndex:
method for your UICollectionView
or set the sectionInset
property of the UICollectionViewFlowLayout
object attached to your UICollectionView
:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
return UIEdgeInsetsMake(top, left, bottom, right);
}
or
UICollectionViewFlowLayout *aFlowLayout = [[UICollectionViewFlowLayout alloc] init];
[aFlowLayout setSectionInset:UIEdgeInsetsMake(top, left, bottom, right)];
Updated for Swift 5
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 25, left: 15, bottom: 0, right: 5)
}
How could we add margin in bottom and top of UICollectionView?
Since your collection view has only 1 section, you need to size the spacing between the different rows/columns inside a section and different items in the same row/column correctly rather than setting an inset for the sections.
UICollectionViewDelegateFlowLayout
has the following two methods you should implement to achieve your goals: collectionView(_:layout:minimumLineSpacingForSectionAt:)
and collectionView(_:layout:minimumInteritemSpacingForSectionAt:)
.
To copy the spacing you currently use for sections, you need to implement those methods like below:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return CGFloat(15)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return CGFloat(15)
}
UICollectionView Top spacing
I haven't worked with UICollectionViewCompositionalLayout.list
, so this is just from some quick research and experimentation...
The default .headerMode
for UICollectionLayoutListConfiguration
is .none
... when using .insetGrouped
that results in the "extra space" we're seeing.
Curiously, there is also a headerTopPadding
property, which we might expect to be of help here. It's default is 0
... but that appears to only be applied if there IS a header view.
So, if we set .headerMode = .supplementary
and return an empty UICollectionReusableView
for the header, we can get rid of the extra space:
Now, the top space is the same as the default left/right padding.
Here's what I used for the header view:
class EmptyHeaderView : UICollectionReusableView {
static let reuseIdentifier:String = "emptyHeaderView"
}
and three edits to your configureCollectionView()
func:
func configureCollectionView() {
var layoutConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
// 1
// we're going to supply an "empty" header supplementary view
layoutConfig.headerMode = .supplementary
let listLayout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
myCollectionView.collectionViewLayout = listLayout
myCollectionView.isScrollEnabled = false
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, CVData> { (cell, indexPath, item) in
var content = UIListContentConfiguration.cell()
content.text = item.name
content.textProperties.font.withSize(8.0)
content.textProperties.font = UIFont.preferredFont(forTextStyle: .body)
content.secondaryText = item.value
content.prefersSideBySideTextAndSecondaryText = true
content.textProperties.adjustsFontSizeToFitWidth = false
cell.contentConfiguration = content
}
dataSource = UICollectionViewDiffableDataSource<Section, CVData>(collectionView: myCollectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, identifier: CVData) -> UICollectionViewCell? in
// Dequeue reusable cell using cell registration (Reuse identifier no longer needed)
let cell = collectionView.dequeueConfiguredReusableCell(using: cellRegistration,
for: indexPath,
item: identifier)
// Configure cell appearance
cell.accessories = [.disclosureIndicator()]
return cell
}
// 2
// register a reusable supplementary view for the header
myCollectionView.register(EmptyHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: EmptyHeaderView.reuseIdentifier)
// 3
// provider for header suppleentary view
dataSource.supplementaryViewProvider = { (collectionView: UICollectionView, kind: String, indexPath: IndexPath) -> UICollectionReusableView? in
if kind == UICollectionView.elementKindSectionHeader {
if let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: EmptyHeaderView.reuseIdentifier, for: indexPath) as? EmptyHeaderView {
return headerView
}
}
fatalError("Something's wrong with the setup...")
}
}
Placing a margin around each edge of the UICollectionView
In
(UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
}
you can give your cells some margin on the left side.
Or you can create custom cells, which have a margin.
or you can set the property .sectionInset of your CollectionviewFlowLayout
, which should be the easiest way (if you use FlowLayout)
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):
Create equal space between cells and between margins and cells UICollectionView
Assuming that you're using UICollectionViewFlowLayout
and your cell has fixed size:
Custom cell code: (I added some shadow and rounded corners, ignore it)
import UIKit
class CollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
layer.shadowColor = UIColor.lightGray.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2.0)
layer.shadowRadius = 5.0
layer.shadowOpacity = 1.0
layer.masksToBounds = false
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath
layer.backgroundColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true
layer.cornerRadius = 10
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
View controller code:
import UIKit
private let reuseIdentifier = "Cell"
class CollectionViewController: UICollectionViewController {
override func viewDidLoad() {
super.viewDidLoad()
/// Class registration
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
/// Expected cell size
let cellSize = CGSize(width: 120, height: 110)
/// Number of columns you need
let numColumns: CGFloat = 2
/// Interitem space calculation
let interitemSpace = ( UIScreen.main.bounds.width - numColumns * cellSize.width ) / (numColumns + 1)
/// Setting content insets for side margins
collectionView.contentInset = UIEdgeInsets(top: 10, left: interitemSpace, bottom: 10, right: interitemSpace)
/// Telling the layout which cell size it has
(self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize = cellSize
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
cell.backgroundColor = .white
return cell
}
}
Here is the result:
Remove inset spacing at bottom of UICollectionView
The final solution that worked for me (for anyone that runs into a similar situation):
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
if section == 0 {
return UIEdgeInsetsMake(0, 0, 0, 1 * UIScreen.main.scale)
} else {
return UIEdgeInsets.zero
}
}
Related Topics
Storyboard View Elements Greyed Out
How to Add a Button to the Mkpointannotation
How to Use a Custom Font with Dynamic Text Sizes in iOS7
How to Attach Debugger to iOS App After Launch
How to Retrieve a File Using Wkwebview
How to Turn the iPhone Camera Flash On/Off
Programmatically Switching Between Tabs Within Swift
Does Swift Support Implicit Conversion
Copy Nsattributedstring in Uipasteboard
iOS - How to Play a Video with Transparency
How to Disable Floating Headers in Uitableview with Uitableviewstyleplain
Change Color of Back Button in Navigation Bar
Programmatically Dial a Phone Number and Pass Dtmf Using the iPhone Sdk
Single Function to Dismiss All Open View Controllers
Crashlytics in iOS Won't Proceed Past "Build Your Project" in Fabric App
Checking for Multiple Asynchronous Responses from Alamofire and Swift