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
and then on the identity inspector
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):
How to load custom cell ( xib) in UICollectionView cell using swift
Here is what you can do,
Change your
MyCustomView
class to be a subclass of UICollectionViewCell and not UIView.Remove
override init(frame : CGRect)
,required init?(coder aDecoder: NSCoder)
,func xibSetup()
,func loadViewFromNib() -> UIView
fromMyCustomView
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.
Finally you will be left with just IBOutlets in MyCustomView.
For better coding practice change the name from MyCustomView to MyCustomCell (optional)
Go to your xib, select the xib and set its class as MyCustomView.
- In the same screen change file owner to yourView controller hosting collectionView
- In ViewDidLoad of your viewController register your nib.
self.collectionView.registerNib(UINib(nibName: "your_xib_name", bundle: nil), forCellWithReuseIdentifier: "your_reusable_identifier")
- 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
- 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
Atomic Properties VS Thread-Safe in Objective-C
Automatic Signing Is Unable to Resolve an Issue with the "Projectname" Target's Entitlements File
How to Get the 3D View of UI in Xcode 6
Read a Text File Line by Line in Swift
How to Know Which Is the Default Measure System (Imperial or Metric) on iOS
Change Font of Back Navigation Bar Button
Access the Instance of a Viewcontroller from Another in Swift
How to Zoom a Uiscrollview Inside of a Uicollectionviewcell
How to Get Uiviewcontroller of a Uiview's Superview in iOS
Set Background Color of Active Tab Bar Item in Swift
Programmatically Get Path to Application Support Folder
Expand and Collapse Tableview Cells
Swiftui: Unwanted Split View on iPad
Swift 3 Objc Optional Protocol Method Not Called in Subclass
Xcode 9 - Localization Issue Warning Storyboard
iOS Changing Uiscrollview Scrollbar Color to Different Colors