Uicollectionview Spacing Margins

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:

Sample Image

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:

  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

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:

Sample Image

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



Leave a reply



Submit