ios – How to create a horizontal scrolling stackView of UIViews using .Xib files

[ad_1]

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 tried New File -> Cocoa Touch Class -> Subclass of: UIView, it disabled the checkbox for also create .xib file. Some example classes that do allow .xib files are the UITableView and UICollectionView.

Since you’re trying to scroll items horizontally, not vertically, I’d guess you don’t want a UITableView. This leaves the UICollectionView. This works a lot like the UITableView, 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 a Reuse Identifier. In my example, I used the string TileReuseIdentifier.

Design the .xib file however you want: to recreate your code, I put a UIImageView above a UILabel.

The WhatsHotTile.swift file will replace what was a subclass of UIView in your code, with the same two IBOutlets:

import UIKit

class WhatsHotTile: UICollectionViewCell {
    @IBOutlet weak var itemName: UILabel!
    @IBOutlet weak var itemImage: UIImageView!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
}

In Main.storyboard, place a UICollectionView 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’s TileReuseIdentifier.

In the ViewController file, create an IBOutlet for the UICollectionView, and inside viewDidLoad, set the collection view’s dataSource to self (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:

override func viewDidLoad() {
   super.viewDidLoad()
        
   collectionOfShoes.dataSource = self
   collectionOfShoes.register(UINib(nibName: "WhatsHotTile", bundle: nil), forCellWithReuseIdentifier: "TileReuseIdentifier")
}

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 the numberOfItemsInSection method to return 1. In conjunction with the following code inside viewDidLayoutSubviews, which happens after viewDidLoad, this will cause the collection view to scroll horizontally instead of vertically as it otherwise would:

override func viewDidLayoutSubviews() {
    // REFERENCE 1:  https://stackoverflow.com/a/32584637/18248018
    // REFERENCE 2:  https://stackoverflow.com/a/59206057/18248018
    let collectionViewFlowControl = UICollectionViewFlowLayout()
    collectionViewFlowControl.itemSize = CGSize(width: 150.0, height: 150.0)
    collectionViewFlowControl.scrollDirection = UICollectionView.ScrollDirection.horizontal
    collectionOfShoes.collectionViewLayout = collectionViewFlowControl
}

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:

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var collectionOfShoes: UICollectionView!
    
    struct Shoe {
        let name: String
        let image: UIImage
    }
    
    var shoes: [Shoe] = [Shoe(name: "Shoe 1", image: UIImage(named: "shoe_1")!), Shoe(name: "Shoe 2", image: UIImage(named: "shoe_2")!), Shoe(name: "Shoe 3", image: UIImage(named: "shoe_3")!), Shoe(name: "Shoe 4", image: UIImage(named: "shoe_1")!), Shoe(name: "Shoe 5", image: UIImage(named: "shoe_2")!), Shoe(name: "Shoe 6", image: UIImage(named: "shoe_3")!), Shoe(name: "Shoe 7", image: UIImage(named: "shoe_1")!), Shoe(name: "Shoe 8", image: UIImage(named: "shoe_2")!), Shoe(name: "Shoe 9", image: UIImage(named: "shoe_3")!)]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        collectionOfShoes.dataSource = self
        collectionOfShoes.register(UINib(nibName: "WhatsHotTile", bundle: nil), forCellWithReuseIdentifier: "TileReuseIdentifier")
    }
    
    override func viewDidLayoutSubviews() {
        // REFERENCE 1:  https://stackoverflow.com/a/32584637/18248018
        // REFERENCE 2:  https://stackoverflow.com/a/59206057/18248018
        let collectionViewFlowControl = UICollectionViewFlowLayout()
        collectionViewFlowControl.itemSize = CGSize(width: 150.0, height: 150.0)
        collectionViewFlowControl.scrollDirection = UICollectionView.ScrollDirection.horizontal
        collectionOfShoes.collectionViewLayout = collectionViewFlowControl
    }
}

extension ViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return shoes.count
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let whatsHotTile = collectionView.dequeueReusableCell(withReuseIdentifier: "TileReuseIdentifier", for: indexPath) as! WhatsHotTile
        whatsHotTile.itemName.text = shoes[indexPath.section].name
        whatsHotTile.itemImage.image = shoes[indexPath.section].image
        return whatsHotTile
    }
}

A picture of the functioning app:

picture of the collection view running in the simulator scrolled horizontally

Credit belongs to William T., matt and Ilker Baltaci for the question and answers I referenced to implement the horizontal scrolling functionality.

[ad_2]

Source link

Leave a Reply

Your email address will not be published.