49

I have created a small sample project using Swift. I have created an "MyCustomView" as xib which contains label, button and imageView as shown in below code:

import UIKit

@IBDesignable class MyCustomView: UIView {

    @IBOutlet weak var lblName: UILabel!
    @IBOutlet weak var btnClick: UIButton!
    @IBOutlet weak var myImageView: UIImageView!

    var view:UIView!

    @IBInspectable
    var mytitleLabelText: String? {
        get {
            return lblName.text
        }
        set(mytitleLabelText) {
            lblName.text = mytitleLabelText
        }
    }

    @IBInspectable
    var myCustomImage:UIImage? {
        get {
            return myImageView.image
        }
        set(myCustomImage) {
            myImageView.image = myCustomImage
        }
    }


    override init(frame : CGRect)
    {
        super.init(frame: frame)
        xibSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        xibSetup()
    }


    func xibSetup()
    {
        view = loadViewFromNib()
        view.frame = self.bounds

        // not sure about this ?
        view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
        addSubview(view)
    }


    func loadViewFromNib() -> UIView {

        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: "MyCustomView", bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView

        return view
    }
}

Attached the image of xib for the reference. Screenshot

In StoryBoard -> ViewController added UIViewCollection which as shown in the below image. In this viewcollection, I need that orange color cell to contain my custom xib to be loaded at runtime.

How do I achieve this?

enter image description here

New Modified code as suggested by Sandeep

// 1 import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.collectionView.register(UINib(nibName: "MyCustomView", bundle: nil), forCellWithReuseIdentifier: "myCell")

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 7
    }

    func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! MyCustomView

        cell.lblName.text = "MyNewName"
        return cell
    }
}

// 2 import UIKit

@IBDesignable class MyCustomView: UICollectionViewCell {

    @IBOutlet weak var lblName: UILabel!
    @IBOutlet weak var btnClick: UIButton!
    @IBOutlet weak var myImageView: UIImageView!

    var view:UIView!

    @IBInspectable
    var mytitleLabelText: String? {
        get {
            return lblName.text
        }
        set(mytitleLabelText) {
            lblName.text = mytitleLabelText
        }
    }

    @IBInspectable
    var myCustomImage:UIImage? {
        get {
            return myImageView.image
        }
        set(myCustomImage) {
            myImageView.image = myCustomImage
        }
    }

}
Mudith Chathuranga Silva
  • 7,253
  • 2
  • 50
  • 58
sia
  • 1,872
  • 1
  • 23
  • 54
  • Please change let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! MyCustomView to let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("myCell", forIndexPath: indexPath) as! MyCustomView – Sandeep Bhandari May 19 '16 at 08:42

4 Answers4

114

Here is what you can do,

  1. Change your MyCustomView class to be a subclass of UICollectionViewCell and not UIView.

  2. Remove override init(frame : CGRect),required init?(coder aDecoder: NSCoder),func xibSetup(),func loadViewFromNib() -> UIView from MyCustomView

  3. I seriously could not understand how are you using your setter and getter for mytitleLabelText and myCustomImage. If its of no use get rid of it as well.

  4. Finally you will be left with just IBOutlets in MyCustomView.

  5. For better coding practice change the name from MyCustomView to MyCustomCell (optional)

  6. Go to your xib, select the xib and set its class as MyCustomView.

enter image description here

  1. In the same screen change file owner to yourView controller hosting collectionView

enter image description here

  1. In ViewDidLoad of your viewController register your nib.
self.collectionView.registerNib(UINib(nibName: "your_xib_name", bundle: nil), forCellWithReuseIdentifier: "your_reusable_identifier")
  1. In cellForItemAtIndexPath,
let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! MyCustomView
cell.lblName.text = "bla bla" //access your Cell's IBOutlets
return cell
  1. Finally in order to control the size of cell either override the delegate of collectionView or simply go to your collectionView select the collectionCell in it and drag it to match your dimension :) Thats it :)

Happy coding. Search tutorials for better understanding. I can't explain all delegates as I'll end up writing a blog here.

starball
  • 20,030
  • 7
  • 43
  • 238
Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
  • Thanks Sandeep for step by step explanation. I will try as suggested above. – sia May 19 '16 at 08:01
  • i tried same way as suggested but nothing is displayed..not sure what could be wrong. – sia May 19 '16 at 08:28
  • @sia : Set the background color for your cell you will see the cells being loaded :) or else change the label text color to white :) – Sandeep Bhandari May 19 '16 at 08:29
  • Can you please post your code with modifications I mentioned. I have a working code with me. No ways its gonna fail :) – Sandeep Bhandari May 19 '16 at 08:35
  • @ Sandeep Bhandari - I have updated the new code above. – sia May 19 '16 at 08:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/112373/discussion-between-sia-and-sandeep-bhandari). – sia May 19 '16 at 09:49
  • @sia : Am glad it did :) Happy coding :) – Sandeep Bhandari May 19 '16 at 11:14
  • @downvoter : Please lemme know why was this down voted? Any way flagged your action already – Sandeep Bhandari Jul 10 '17 at 13:01
  • @SandeepBhandari can you check this question I posted- https://stackoverflow.com/questions/45021199/uicollectionviewcell-from-xib-file-not-showing-up-in-uicollectionview. I can't seem to get it to work. The only difference is that my collectionView and cell are both in separate xib files but my `cellForItemAt` function is not being called at all for some reason. – Anjan Biswas Jul 10 '17 at 21:35
  • What if I want to reuse the cell in collection views in different view controllers? – Yannis P. Mar 29 '18 at 14:29
  • 1
    @yannis-p : Sorry saw your message now, wasn't really active on SO for quite sometime, I hope you got your answer by now, but if not, if you would like to use same xib/cell accross multiple ViewControllers you can skip step 7 :) Thats all follow other steps as is n there shouldn't be any issue :) – Sandeep Bhandari Apr 06 '18 at 15:33
  • 1
    I actually just ended up making the cell/presentation customizable, but I'm reusing the same logic for many different screen just with different content which is better. But thanks your answer will be useful in the future when I decided to reuse UI :) – Yannis P. Apr 07 '18 at 18:04
  • @yannis-p : Always welcome :) Ill be glad if my answer helps u in anyway in future :) – Sandeep Bhandari Apr 07 '18 at 19:37
  • @SandeepBhandari I've followed what you've written here and the cell displays when I run the app, but I can't get it to render in Interface Builder. Is there anything else needed to get it to render in IB? I threw in `awakeFromNib` & `prepareForInterfaceBuilder` with a `setup` method that's called by both of those methods. – Adrian May 17 '18 at 15:10
  • 1
    Your step-by-step worked perfectly. Thanks! (iOS 13 / Swift 5) – rommex Nov 13 '19 at 12:11
  • 1
    `registerNib` has been renamed to `register`. Small update to Step #8 ;) – Vexy Jan 04 '20 at 19:40
  • Isn't the purpose of using a xib to make the cell reusable across a project? Doesn't that defeat the purpose if you are setting the owner of the cell as a specific ViewController? – ScottyBlades May 27 '21 at 17:20
19

For Swift 4.0

in viewDidLoad:

//custom collectionViewCell
mainCollectionView.register(UINib(nibName: "your_customcell_name", bundle: nil), forCellWithReuseIdentifier: "your_customcell_identifier")

in cellForItemAt indexPath:

let cell : <your_customcell_name> = mainCollectionView.dequeueReusableCell(withReuseIdentifier: "your_customcell_identifier", for: indexPath) as! <your_customcell_name>

And dont forget to set identifier for your custom cell in xib section.

Raj Aryan
  • 363
  • 2
  • 15
5

One line approach if you have to register multiple cells.

extension UICollectionViewCell {

    static func register(for collectionView: UICollectionView)  {
        let cellName = String(describing: self)
        let cellIdentifier = cellName + "Identifier"
        let cellNib = UINib(nibName: String(describing: self), bundle: nil)
        collectionView.register(cellNib, forCellWithReuseIdentifier: cellIdentifier)
    }
}

Steps on how to use

  1. Name your Cell identifier as "YourcellName" + "Identifier" eg: CustomCellIdentifier if your cell name is CustomCell.

  2. CustomCell.register(for: collectionView)

Bhuvan Bhatt
  • 3,276
  • 2
  • 18
  • 23
0

For Swift 4.2 in viewDidLoad

 self.collectionView.register(UINib(nibName: "your_xib_name", bundle: nil), forCellWithReuseIdentifier: "your_reusable_identifier")

in cellForItemAt indexPath:

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "your_reusable_identifier", for: indexPath) as! MyCustomView

And of course as @Raj Aryan said: don't forget to set identifier for your custom cell in xib section.

Ben Shabat
  • 388
  • 4
  • 17