How to add an UICollectionViewLayout programmatically?
Asked Answered
E

4

7

I'm trying to setup a UICollectionViewLayout programmatically. I'm using a UICollectionView also without using storyboards, as well as settings its constraints.

I've followed Ray Wenderlich tutorial on the subject with some changes to adapt the code to Swift 3 (as AZCoder2 did https://github.com/AZCoder2/Pinterest).

Since all these examples uses storyboards, I've also introduced some changes to create the UICollectionView and its UICollectionViewLayout:

collectionViewLayout = PinterestLayout()
collectionViewLayout.delegate = self
collectionView = UICollectionView.init(frame: .zero, collectionViewLayout: collectionViewLayout)

The result: I can't see anything. If I change the UICollectionViewLayout with the one that Apple provides (UICollectionViewFlowLayout), at least I can see the cells with their content. If I implement some changes and use the storyboard, everything works great but it's not the way I want to accomplish this. The whole view is made programmatically and the collection view is a part of it.

What am I missing? Is it something to do with the way I instantiate the UICollectionViewLayout? Do I have to register something (for example, as I need to register the reusable cell)?

Easing answered 12/7, 2017 at 23:50 Comment(4)
I'm assuming this code is in a view controller. Is it a subclass of UICollectionViewController?Nievelt
No, @Jumhyn... it's a UIViewController... why would I need a UICollectionViewController?Easing
github.com/satishVekariya/PushpaCollectionViewLayoutEarthstar
Thanks, @SPatel. I managed to solve this more than a year ago. But thanks anyway. I appreciate that.Easing
S
8

How about you just create a variable that creates your flow layout for you like this

var flowLayout: UICollectionViewFlowLayout {
    let _flowLayout = UICollectionViewFlowLayout()

    // edit properties here
    _flowLayout.itemSize = CGSize(width: 98, height: 134)
    _flowLayout.sectionInset = UIEdgeInsetsMake(0, 5, 0, 5)
    _flowLayout.scrollDirection = UICollectionViewScrollDirection.horizontal
    _flowLayout.minimumInteritemSpacing = 0.0
    // edit properties here

    return _flowLayout
}

And then you can set it by calling the variable.

self.collectionView.collectionViewLayout = flowLayout // after initializing it another way
// or
UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
Shull answered 13/7, 2017 at 12:51 Comment(5)
Thanks, Zonily Jame. Actually, I'm using a custom layout not a UICollectionViewFlowLayout. Both, my custom layout and the one you mentioned, inherit from the abstract class UICollectionViewLayout. But a custom layout needs a lot of coding to make it work. I tried your suggestion though... with some changed. But doesn't work. Thanks anyway!Easing
Hello I am also using custom layout in my UICollectionViewController and I want to display button at the bottom so how can i do this in UICollectionViewController?? @LeandroSw
@ParthBarot in this case I think you should just use container views.Shull
I Didn't get it @ZonilyJame Can you please give some example?Sw
@ParthBarot You should be using layoutAttributesForSupplementaryView or layoutAttributesForDecotarionView. This article is a good starting point: objc.io/issues/3-views/collection-view-layouts. Maybe you can download the example project and try to understand it. I suggest to read the full article though. Best of lucks.Easing
J
2

I think this will work.

override init(collectionViewLayout layout: UICollectionViewLayout) {
    super.init(collectionViewLayout: layout)
    collectionView?.collectionViewLayout = YourCollectionViewLayout()
}
Jeanniejeannine answered 22/8, 2018 at 7:33 Comment(0)
E
1

It's possible to do what I was trying to do. Basically, follow the tutorials I suggested in my own question and setup the collection view and its view layout as follow:

collectionViewLayout = PinterestLayout()
collectionViewLayout.delegate = self
collectionView = DynamicCollectionView.init(frame: .zero, collectionViewLayout: collectionViewLayout)

Note that I'm using DynamicCollectionView (instead of UICollectionView). This class is not provided by Apple: I've made my own using the code provided in this post.

Remember that this approach is when you're creating a view programmatically, using constraints. (May be it has another cases of use)

Easing answered 14/7, 2017 at 1:12 Comment(0)
G
0

I resolved this issue taking these steps:

1 - Changing UICollectionViewController to a UIViewController with a collectionView inside.

2 - On ViewDidLoad I set the delegates and add the view, as usual. Moreover, I instantiate the ViewLayout and use it to instantiate the CollectionView

  var collectionView: UICollectionView?




override func viewDidLoad() {
super.viewDidLoad()

navigationController!.isToolbarHidden = true

let layout = MosaicViewLayout()
layout.delegate = self

collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

guard let collectionView = collectionView else {
  return
}

view.addSubview(collectionView)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(PhotoCell.self, forCellWithReuseIdentifier: "CharacterCell")
setupCollectionConstraints()

}

3 - On the ViewLayout the protocol stays like this:

protocol MosaicViewLayoutDelegate:class {


func collectionView(_ collectionView: UICollectionView,
                  heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat
}

Don't forget to add the instance inside the class

  weak var delegate: MosaicViewLayoutDelegate?

4 - Add the delegate extension to you ViewController

extension HomeViewImpl: MosaicViewLayoutDelegate {
func collectionView(_ collectionView: UICollectionView, heightForItemAtIndexPath indexPath: IndexPath) -> CGFloat {
let random = arc4random_uniform(4) + 1
return CGFloat(random * 100)
 }
}

enter code here

Gutsy answered 6/12, 2021 at 23:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.