Reputation: 1820
I have multiple collection views that need to use the same prototype cells. Right now, I'm duplicating the prototype cells in each collection view in storyboard (as seen below). This is not very DRY and becomes a pain when making storyboard changes to the cells.
Is it possible to define the cell in one place in storyboard?
Alternatively I tried using only 1 collection view, but I couldn't get the 3 column layout where cells stack and scroll vertically, so I moved to 3 collections views.
Upvotes: 3
Views: 3231
Reputation: 63379
I built a cool/useful abstraction over the trick Robert J. Clegg's shoed above.
I cut/pasted all my NSTableViewCell
s into a new XIB, which I called SharedTableCellViews.xib
. To keep track of its contents, I made an accompanying SharedTableCellViews
struct, as such:
import AppKit
/// Models the multiple NSTableCellViews contained within SharedTableCellViews.nib, which can be defined centrally, and reused
/// between multiple `NSTableView`s or `NSOutlineView`s (which are just a subclass thereof)
struct SharedTableCellViews {
typealias ID = NSUserInterfaceItemIdentifier
static let shared = SharedTableCellViews()
static let nibName = "SharedTableCellViews"
static let textWithIcon = ID(rawValue: "NameAndIconTableCellView")
static let numericText = ID(rawValue: "NumericTextTableCellView")
static let normalText = ID(rawValue: "TextTableCellView")
static let monospacedText = ID(rawValue: "MonoSpacedTextTableCellView")
static let allIDs = [
textWithIcon,
numericText,
normalText,
monospacedText,
]
let nib = NSNib(nibNamed: nibName, bundle: nil)
func register(viewIDs: [NSUserInterfaceItemIdentifier] = allIDs, forUseBy tableView: NSTableView) {
for viewID in viewsIDs {
precondition(SharedTableCellViews.allIDs.contains(viewID), "The nib name \(viewID) " +
"is not one of the viewIDs managed by \(SharedTableCellViews.self).")
tableView.register(self.nib, forIdentifier: viewID)
}
}
}
The register(viewIDs:forUseBy:)
method allows me to only need a single line from my view controller to set up a table:
SharedTableCellViews.shared.register(forUseBy: self.someTableView)
The same nib object (SharedTableCellViews.shared.nib
) is reused by all tables, for every reuse identifier. The key is to set the identifiers of each NSTableCellView
s within the one xib file.
This also acts nicely as a central namespace to store all my NSUserInterfaceItemIdentifier
, which I could directly use with NSTableView.makeView(withIdentifier:owner:)
s.
Everything here is for MacOS/AppKit, but should be equally applicable to iOS/UIKit with just a few NS
-> UI
renamings.
Upvotes: 0
Reputation: 7370
Yes this is possible. I never design cells (UITableView
or UICollectionView
cells ) in the storyboard. Chances are, you'll need to reuse them as is the case here.
To begin with, create a new view (File > New > File) and select the View option from the User Interface section. It doesn’t matter which device family you choose, so give it a name (I’m calling mine NibCell). It will open up in the canvas – the first job is to delete the existing view, and drag in a Collection View Cell from the Object Browser.
You would also create a subclass of UICollectionViewCell
class and set it to the class of the xib file in interface builder.
Once you have created the xib and wired up the elements to the custom class - you need to register it like so in your class that has the UICollectionView
in it (don't forget to import it the custom cell class first!)
UINib *cellNib = [UINib nibWithNibName:@"NibCell" bundle:nil];
[self.collectionView registerNib:cellNib forCellWithReuseIdentifier:@"cvCell"];
And you would use it like so:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"cvCell";
CVCell *cell = (CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
//Setup the cell for use
return cell;
}
And thats generally all there is to it. Hope this helps!
Upvotes: 6