Left Align Cells in Uicollectionview

Left Align Cells in UICollectionView

The other solutions in this thread do not work properly, when the line is composed by only 1 item or are over complicated.

Based on the example given by Ryan, I changed the code to detect a new line by inspecting the Y position of the new element. Very simple and quick in performance.

Swift:

class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout {

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)

var leftMargin = sectionInset.left
var maxY: CGFloat = -1.0
attributes?.forEach { layoutAttribute in
if layoutAttribute.frame.origin.y >= maxY {
leftMargin = sectionInset.left
}

layoutAttribute.frame.origin.x = leftMargin

leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing
maxY = max(layoutAttribute.frame.maxY , maxY)
}

return attributes
}
}

If you want to have supplementary views keep their size, add the following at the top of the closure in the forEach call:

guard layoutAttribute.representedElementCategory == .cell else {
return
}

Objective-C:

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

CGFloat leftMargin = self.sectionInset.left; //initalized to silence compiler, and actaully safer, but not planning to use.
CGFloat maxY = -1.0f;

//this loop assumes attributes are in IndexPath order
for (UICollectionViewLayoutAttributes *attribute in attributes) {
if (attribute.frame.origin.y >= maxY) {
leftMargin = self.sectionInset.left;
}

attribute.frame = CGRectMake(leftMargin, attribute.frame.origin.y, attribute.frame.size.width, attribute.frame.size.height);

leftMargin += attribute.frame.size.width + self.minimumInteritemSpacing;
maxY = MAX(CGRectGetMaxY(attribute.frame), maxY);
}

return attributes;
}

align single UICollectionViewCell to the left of the collectionView

Since sectionInset is the same as func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { } protocol, one could call this protocol to know which section has only one cell left.

You can replace :

flowLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

With:

  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

if collectionView.numberOfItems(inSection: section) == 1 {

let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout

return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: collectionView.frame.width - flowLayout.itemSize.width)

}

return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

}

This red cell is the only one left in the second section , and it is left aligned:

Sample Image

Autoresize UICollectionView cells, Align cell to top

So I worked around this for quite a bit. No answers from stack overflow help in any way. So i played with custom UICollectionViewFlowLayout method layoutAttributesForElements.

This method will call for every section, and will have layoutAttributesForElements for rect. This will give an array of UICollectionViewLayoutAttributes which one can modify as per the need.

I was having problem figuring out the y coordinate which I would like to change for my cells.

So first with a loop in attributes from layoutAttributesForElements I got the header and saved it's height in a variable. Then changed the rest of cell's y coordinate with the headerHeight value.

Not sure if this is the right way or not, nor did any performance testing. For now everything seems fine without any lag or jerk.

Here is full code or custom UICollectionViewFlowLayout.


class MainCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

let attr = super.layoutAttributesForElements(in: rect)
var attributes = [UICollectionViewLayoutAttributes]()
for itemAttributes in attr! {
let itemAttributesCopy = itemAttributes.copy() as! UICollectionViewLayoutAttributes
// manipulate itemAttributesCopy
attributes.append(itemAttributesCopy)
}

if attributes.count == 1 {

if let currentAttribute = attributes.first {
currentAttribute.frame = CGRect(x: self.sectionInset.left, y: currentAttribute.frame.origin.y, width: currentAttribute.frame.size.width, height: currentAttribute.frame.size.height)
}
} else {
var sectionHeight: CGFloat = 0

attributes.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .supplementaryView else {
return
}

if layoutAttribute.representedElementKind == UICollectionView.elementKindSectionHeader {
sectionHeight = layoutAttribute.frame.size.height
}
}

attributes.forEach { layoutAttribute in
guard layoutAttribute.representedElementCategory == .cell else {
return
}

if layoutAttribute.frame.origin.x == 0 {
sectionHeight = max(layoutAttribute.frame.minY, sectionHeight)
}

layoutAttribute.frame = CGRect(origin: CGPoint(x: layoutAttribute.frame.origin.x, y: sectionHeight), size: layoutAttribute.frame.size)

}
}
return attributes
}
}

NOTE: You need to copy the attributes in an array first to work with. Else xcode will yell Logging only once for UICollectionViewFlowLayout cache mismatched frame in console.

If any new/perfect solution is there please let me know.

CHEERS!!!

Aligning right to left on UICollectionView with contents

In viewDidLoad():

 let alignedFlowLayout = collectionView.collectionViewLayout as? AlignedCollectionViewFlowLayout
collectionView.transform = CGAffineTransform(scaleX: -1, y: 1)
[enter link description here][1]alignedFlowLayout?.horizontalAlignment = .left

@Hemang comment worked for me.

If you have any subviews in your cell, then you have transform it as well. For e.g.

self.titleLabel.transform = CGAffineTransform(scaleX: -1, y: 1)

AlignedCollectionViewFlowLayout

Left align a UICollectionView

It seems the question should read, left align a UICollectionView.

The simplest solution is to go to:

https://github.com/mokagio/UICollectionViewLeftAlignedLayout

And subclass your layout to this, this will ensure your UICollectionView left aligns, you should set all your insets to 0 first then begin changing them according to your design.

How Can I align the colectionViewCells to the left?

You can manage your cell with below code. Do not forget to add UICollectionViewDelegateFlowLayout

func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
// your code here
}

Aligning right to left on UICollectionView

You can get similar result by performing a transform on the collection view and reverse the flip on its content:

First when creating the UICollectionView I performed a horizontal flip on it:

[collectionView_ setTransform:CGAffineTransformMakeScale(-1, 1)];

Then subclass UICollectionViewCell and in here do the same horizontal flip on its contentView:

[self.contentView setTransform:CGAffineTransformMakeScale(-1, 1)];


Related Topics



Leave a reply



Submit