Create Uicollectionviewcell Subclass with Xib

Create UICollectionViewCell subclass with xib

Make sure the cell on the .xib file know what's the type of the cell.

Select the cell on your interface builder

Sample Image

and then on the identity inspector

Sample Image

Subsequently associate your labels with your properties. (I think you already did that)

Then I'd recommend to verify if you already loaded the .xib file on your cellForItemAtIndexPath: method

NSString *identifier = @"MyCell";    

static BOOL nibMyCellloaded = NO;

if(!nibMyCellloaded)
{
UINib *nib = [UINib nibWithNibName:@"MyCell" bundle: nil];
[cv registerNib:nib forCellWithReuseIdentifier:identifier];
nibMyCellloaded = YES;
}

iOS: Subclassing a subclassed UICollectionViewCell with same outlets/layout, but without second xib?

I think you'll find it much (much) easier if you use "code" classes rather than a xib.

Define a "base" cell class with all your "common" elements.

Make each addition cell class subclasses of your base cell, each with its own "distinct" elements.

Here is a quick, very simple example:

  • the "base" class adds a label at the top
  • the "first" cell subclass adds a Green label below the base class's label, and sets background color to Dark Green
  • the "second" cell subclass adds a Blue label below the base class's label, and sets background color to Cyan
  • for variety, the "third" cell subclass adds two Red labels below the base class's label, and sets background color to Orange

The only thing this needs is a View Controller in your Storyboard set to TestViewController class, and a default Collection View added and connected to @IBOutlet weak var collectionView: UICollectionView!:

class BaseCollectionViewCell: UICollectionViewCell {

let baseLabel = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
commonBaseInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonBaseInit()
}
func commonBaseInit() -> Void {
baseLabel.textAlignment = .center
baseLabel.font = UIFont.systemFont(ofSize: 15.0)
baseLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(baseLabel)
NSLayoutConstraint.activate([
baseLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4.0),
baseLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4.0),
baseLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4.0),
])
// so we can see it easily
baseLabel.backgroundColor = .yellow
}
}

class FirstCollectionViewCell: BaseCollectionViewCell {

let firstLabel = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
commonSubInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonSubInit()
}
func commonSubInit() -> Void {
firstLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(firstLabel)
NSLayoutConstraint.activate([
firstLabel.topAnchor.constraint(equalTo: baseLabel.bottomAnchor, constant: 8.0),
firstLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4.0),
firstLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4.0),
firstLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4.0),
])
firstLabel.textAlignment = .center
// so we can see it easily
firstLabel.backgroundColor = .green
contentView.backgroundColor = UIColor(red: 0.0, green: 0.6, blue: 0.0, alpha: 1.0)
}

}

class SecondCollectionViewCell: BaseCollectionViewCell {

let secondLabel = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
commonSubInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonSubInit()
}
func commonSubInit() -> Void {
secondLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(secondLabel)
NSLayoutConstraint.activate([
secondLabel.topAnchor.constraint(equalTo: baseLabel.bottomAnchor, constant: 8.0),
secondLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4.0),
secondLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4.0),
secondLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4.0),
])
secondLabel.textAlignment = .center
// so we can see it easily
secondLabel.backgroundColor = .blue
secondLabel.textColor = .white
contentView.backgroundColor = .cyan
}

}

class ThirdCollectionViewCell: BaseCollectionViewCell {

let thirdLabel = UILabel()
let anotherLabel = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
commonSubInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonSubInit()
}
func commonSubInit() -> Void {
thirdLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(thirdLabel)
anotherLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(anotherLabel)
NSLayoutConstraint.activate([
thirdLabel.topAnchor.constraint(equalTo: baseLabel.bottomAnchor, constant: 8.0),
thirdLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4.0),

anotherLabel.topAnchor.constraint(equalTo: baseLabel.bottomAnchor, constant: 8.0),
anotherLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4.0),

anotherLabel.leadingAnchor.constraint(equalTo: thirdLabel.trailingAnchor, constant: 4.0),
anotherLabel.widthAnchor.constraint(equalTo: thirdLabel.widthAnchor),

thirdLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4.0),
])
thirdLabel.textAlignment = .left
anotherLabel.textAlignment = .right
// so we can see it easily
thirdLabel.backgroundColor = .red
thirdLabel.textColor = .yellow
anotherLabel.backgroundColor = .red
anotherLabel.textColor = .yellow
contentView.backgroundColor = .orange
}

}

class TestViewController: UIViewController, UICollectionViewDataSource {

@IBOutlet weak var collectionView: UICollectionView!

override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.dataSource = self
self.collectionView.register(FirstCollectionViewCell.self, forCellWithReuseIdentifier: "firstCell")
self.collectionView.register(SecondCollectionViewCell.self, forCellWithReuseIdentifier: "secondCell")
self.collectionView.register(ThirdCollectionViewCell.self, forCellWithReuseIdentifier: "thirdCell")
}

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

var cell: UICollectionViewCell?

switch indexPath.row % 3 {
case 1:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "secondCell", for: indexPath)
if let c = cell as? SecondCollectionViewCell {
// set "Second Cell" specific properties
c.secondLabel.text = "\(indexPath.item)"
}

case 2:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "thirdCell", for: indexPath)
if let c = cell as? ThirdCollectionViewCell {
// set "Third Cell" specific properties
c.thirdLabel.text = "\(indexPath.item)"
c.anotherLabel.text = "A"
}

default:
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "firstCell", for: indexPath)
if let c = cell as? FirstCollectionViewCell {
// set "First Cell" specific properties
c.firstLabel.text = "\(indexPath.item)"
}

}

if let c = cell as? BaseCollectionViewCell {
// set base (common) properties, if they change
c.baseLabel.text = "Common Label \(indexPath)"
}

guard let c = cell else {
fatalError("We did something wrong!")
}
return c
}

}

Example output (30 cells, rotating through first, second and third cell classes):

Sample Image

How to load custom cell ( xib) in UICollectionView cell using swift

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.

Sample Image


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

Sample Image


  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.

Happy coding

Subclassing UICollectionViewCell and initialising from xib

Where are you calling registerNib?

I reproduced the setup to match what i can tell from yours.

This works for me, no errors :

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

var model:[String] = []

@IBOutlet weak var collectionView: UICollectionView!

override func viewDidLoad() {
super.viewDidLoad()

// just a simple test model ...
for index in 1...100 {
model.append("\(index)")
}

// register the nib
collectionView.registerNib(UINib(nibName: "ItemCell", bundle: nil), forCellWithReuseIdentifier: "ItemCell")

// this is just a test layout
var layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width:200.0,height:200.0)
layout.scrollDirection = UICollectionViewScrollDirection.Vertical
self.collectionView.collectionViewLayout = layout
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.reloadData()
}

// MARK: - UICollectionViewDataSource
func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int{
return model.count
}

func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell{
var cell:UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("ItemCell", forIndexPath: indexPath) as! UICollectionViewCell
return cell
}
}

Subclass UICollectionViewController with xib

If a view controller's UI is specified in a xib, then you have to instantiate it with a call to [[MyCollectionViewController alloc] initWithNibName:@"MyCollectionViewController" inBundle:[NSBundle mainBundle]] (or however you get your bundle). When you use this constructor, then the view controller's outlets get wired up properly, and the layout is set based on what's in the xib.



Related Topics



Leave a reply



Submit