Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop Single UICollectionView cell Flowing to the centre of the screen

I am trying to understand why Collection View keeps centre aligning just the last cell in a collection.
I have created a simple Flow layout based collection view. I am using the Autolayout flag - which I am not sure is causing this issue.

Whenever I remove a cell from the Collection view - the first few seem to work fine and roll to the left. However when I remove the second last one, then suddenly the last cell changes from being left aligned to being centre aligned. Does anyone have an explanation? It seems strange.

How do I make it so that all the cells will roll to the left and stay aligned to the left.

Edit: here is the view hierachy debugging: http://imgur.com/a/NxidO

Here is the view Behaviour

Collectionview centring

I have made a simple github to demo it: https://github.com/grantkemp/CollectionViewIssue

and here is the code:

        var dataforCV = ["short","longer phrase", "Super long Phrase"]

override func viewDidLoad() {
        super.viewDidLoad()
        demoCollectionView.reloadData()
    let layout = UICollectionViewFlowLayout()

    // Bug Description  - > UICollectionViewFlowLayoutAutomaticSize will center Align the layout if it has only a single cell - but it will left align the content if there is more than one cell.

    // I would expect this behaviour to be consistently left aligning the content.

    //How to repeat: If you comment out UICollection​View​Flow​Layout​Automatic​Size then the collection view will show 3 cells being left aligned and it will continue to left align all the content no matter how many cells you remove.

    // But: if you leave turn UICollection​View​Flow​Layout​Automatic​Size on - then it will intially show 3 cells being left aligned, and then as you click to remove each cell they will stay left aligned until the last single cell will suddenly center align in the collection view

    //  see here for the screen recording:https://i.stack.imgur.com/bledY.gif
    //  see here for the view hierachy debuggins screen: http://imgur.com/a/NxidO

    layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize


    // <-- End Bug Description
    demoCollectionView.collectionViewLayout = layout
}

    //MARk: CollectionView

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? collectionCell
        cell?.text.text  = dataforCV[indexPath.row]

        return cell!

    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dataforCV.count
    }
    //Remove the item from the array if selected
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        dataforCV.remove(at: indexPath.row)
        demoCollectionView.deleteItems(at: [indexPath])
    }
like image 982
UKDataGeek Avatar asked Apr 06 '17 22:04

UKDataGeek


People also ask

How do you make a centered UICollectionView like in Spotify's player?

The center of the collectionView can be found using this nifty method: CGPoint point = [self. view convertPoint:*yourCollectionView*. center toView:*yourCollectionView]; Now set up a rule, that if the cell's center is further than x away, the size of the cell is for example the 'normal size', call it 1.

What is UICollectionView flow layout?

Overview. A flow layout is a type of collection view layout. Items in the collection view flow from one row or column (depending on the scrolling direction) to the next, with each row containing as many cells as will fit. Cells can be the same sizes or different sizes.

How does swift implement UICollectionView?

Add a CollectionView by pressing command shift L to open the storyboard widget window. Drag the collectionView onto the main view controller. Add constraints to the UICollectionView widget to ensure that the widget fills the screen on all devices. The foundation is now set up in the storyboard.


2 Answers

I managed to solve this using the below two steps:

  1. Logged a bug with Apple about the strange behaviour I noticed about the cell behaviour changing when using the UICollectionViewFlowLayoutAutomaticSize
  2. I did a workaround by creating a modified CustomViewFlowLayout ( can't find the original SO/github question where I saw this approach used - I will add it if I find it) I then added the UICollectionViewFlowLayoutAutomaticSize setting - and it's working beautifully.

Sample code:

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

        let attributes = super.layoutAttributesForElements(in: rect)

        var leftMargin = sectionInset.left
        var maxY: CGFloat = 2.0

        let horizontalSpacing:CGFloat = 5

        attributes?.forEach { layoutAttribute in
            if layoutAttribute.frame.origin.y >= maxY
                || layoutAttribute.frame.origin.x == sectionInset.left {
                leftMargin = sectionInset.left
            }

            if layoutAttribute.frame.origin.x == sectionInset.left {
                leftMargin = sectionInset.left
            }
            else {
                layoutAttribute.frame.origin.x = leftMargin
            }

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

        return attributes
    }

In the ViewController - you have to add the flow layout to the collection view to make it work:

let layout = MyLeftCustomFlowLayout() 
layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
myCollectionViewReference.collectionViewLayout = layout

I think the implementation for Collection View can definitely be simplified but I am going to look into it more as I can see how powerful it is.

like image 170
UKDataGeek Avatar answered Oct 01 '22 05:10

UKDataGeek


In Swift 5

Use UICollectionViewFlowLayout to align cell to left like below

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
self.collectionView.collectionViewLayout = layout
like image 34
Abdul Karim Khan Avatar answered Oct 01 '22 06:10

Abdul Karim Khan