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:
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
Nsurlsession/Nsurlconnection Http Load Failed on iOS 9
Evenly Space Multiple Views Within a Container View
Swift - Get Device'S Wifi Ip Address
Ios 9 Not Opening Instagram App With Url Scheme
How to Present Uialertcontroller When Not in a View Controller
How to Find Topmost View Controller on Ios
How to Adjust the Anchor Point of a Calayer, When Auto Layout Is Being Used
Number of Days Between Two Nsdates
Ios App With Framework Crashed on Device, Dyld: Library Not Loaded, Xcode 6 Beta
Array Extension to Remove Object by Value
Convert Utf-8 Encoded Nsdata to Nsstring
Bold & Non-Bold Text in a Single Uilabel
Nsfilemanager.Defaultmanager().Fileexistsatpath Returns False Instead of True
How to Check If a String Contains Another String in Objective-C
How to Send Mail from an Iphone Application
How to Set the Cookies to Be Used by a Wkwebview