I want to create a horizontal scrolling stackView of UIViews using .Xib files, So far I’ve created the .Xib storyboard as well as the cocoaTouch class that goes along with it and am having trouble setting it up since this is my first time working with .Xib files.
I want the output to look something like this:
But when I run the app it throws this error: Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x6000029f13d0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key itemImage.'
and I don’t know why this is happening since I’m very unfamiliar with .Xib files.
I’ve set the file owner’s class to the WhatsHotTile
class as well as the view itself.
Here is the WhatsHotTile
class:
class WhatsHotTile: UIView {
@IBOutlet weak var itemName: UILabel!
@IBOutlet weak var itemImage: UIImageView!
}
And here is the code where I attempt to create the horizontal scrolling stackView:
for shoe in Shoes {
if shoe.trending == true {
if let whatsHotTile = Bundle.main.loadNibNamed("WhatsHotTile", owner: nil, options: nil)!.first as? WhatsHotTile {
whatsHotTile.itemName.text = shoe.name
whatsHotTile.itemImage.image = shoe.image
whatsHotStackView.addArrangedSubview(whatsHotTile)
}
}
}
One thing that I haven’t done that may or may not need to be done is adding a blank UIView within the horizontal stackView that’s inside of the the scrollView. Is that something that needs to be done or does doing it completely programatically work?
Since this is my first time working with .Xib files could someone explain why this error is occurring / how to fix it as well as what’s the proper way to create .Xib files and use them within your code, if so that would be very much appreciated.
2
Answers
The issue (I believe) is that only some Cocoa Touch classes support .xib files, and
UIView
is not one of those. When I opened up Xcode and triedNew File -> Cocoa Touch Class -> Subclass of: UIView
, it disabled the checkbox foralso create .xib file
. Some example classes that do allow .xib files are theUITableView
andUICollectionView
.Since you’re trying to scroll items horizontally, not vertically, I’d guess you don’t want a
UITableView
. This leaves theUICollectionView
. This works a lot like theUITableView
, so using what I already knew about table views, plus this Stack Overflow post linked here:Q: UICollectionView: One Row or Column
A: https://stackoverflow.com/a/32584637/18248018
and A: https://stackoverflow.com/a/59206057/18248018
I got it to work the way you described. Here is a simple working example:
First, create a new Cocoa Touch class file as a subclass of
UICollectionView
, and check the ‘also create .xib file’ box. I named this subclass ‘WhatsHotTile’, to stay close to your original code.In the Attributes Inspector panel of the
WhatsHotTile
.xib storyboard, set it aReuse Identifier
. In my example, I used the stringTileReuseIdentifier
.Design the .xib file however you want: to recreate your code, I put a
UIImageView
above aUILabel
.The
WhatsHotTile.swift
file will replace what was a subclass ofUIView
in your code, with the same twoIBOutlets
:In
Main.storyboard
, place aUICollectionView
inside your view controller. It will come already initialized with a prototype cell: set this cell’s identifier (in the Attributes Inspector) to the same identifier you chose for the .xib file (in the example, it’sTileReuseIdentifier
.In the
ViewController
file, create anIBOutlet
for theUICollectionView
, and insideviewDidLoad
, set the collection view’sdataSource
toself
(referring to the view controller). Then, and this is the key step to get the .xib files to work with your code,register
the nib for the collection view, using the syntax in the example code below:Then you’ll have to implement the data source methods for the collection view. I usually do this in an extension (included in the complete view controller code at the bottom of this answer). In addition to the two required methods, also define
numberOfSections
and set it to the length of your ‘shoes’ array. Then, set thenumberOfItemsInSection
method to return 1. In conjunction with the following code insideviewDidLayoutSubviews
, which happens afterviewDidLoad
, this will cause the collection view to scroll horizontally instead of vertically as it otherwise would:After these steps, you should wind up with something not too different from your original code, which looks similar to the image reference you provided as your target behavior. Here is the complete code inside
ViewController
:A picture of the functioning app:
Credit belongs to William T., matt and Ilker Baltaci for the question and answers I referenced to implement the horizontal scrolling functionality.
I recommend using UICollectionView here instead of UIStackView as it supports dynamic data and scrolling by default.