【Swift】TableViewのなかにCollectionViewを入れる

#はじめに
TableViewのなかにCollectionViewを入れて縦にも横にもスワイプできるようなものをつくってみましょう。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/a71b593e-b04a-08a5-d81a-c57814d68503.gif)


#GitHub
https://github.com/0429oonishi/TableViews/tree/develop

#手順
1.好きな画像を好きな枚数`Assets.xcassets`に入れる。
2.`ViewController`に`UITableView`を画面の大きさと同じサイズのレイアウトを張る。
3.`Model`を用意する

```swift
struct Model {
    let text: String
    let imageName: String
    init(text: String, imageName: String) {
        self.text = text
        self.imageName = imageName
    }
}
```
4.カスタムテーブルビューセルを用意する。(`CollectionTableViewCell`)
このカスタムセルがテーブルビューの一つのセルなので、以下のようにカスタムセルに`UICollectionView`を貼りましょう。
![スクリーンショット 2021-03-31 14.49.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/97cd09a7-d858-8ef8-b9d5-a719d97ee2ef.png)
5.コレクションビューのカスタムセルを用意する。(`MyCollectionViewCell`)
これがコレクションビューに表示されるセルなので、`image`と`label`をここに貼ります。
![スクリーンショット 2021-03-31 14.50.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/b19d4541-4113-f240-e541-b7557e79e002.png)
6.ViewControllerの実装
`ViewController`の`tableView`に`CollectionTableViewCell`を登録してあげます。

```swift:ViewController
final class ViewController: UIViewController {

    @IBOutlet private weak var tableView: UITableView!
    private var models = [Model]()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        for _ in 1...10 {
            models.append(Model(text: "swift", imageName: "swift"))
            models.append(Model(text: "java", imageName: "java"))
            models.append(Model(text: "ruby", imageName: "ruby"))
            models.append(Model(text: "python", imageName: "python"))
        }

        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(CollectionTableViewCell.nib(), forCellReuseIdentifier: CollectionTableViewCell.id)
        
    }

}

extension ViewController: UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 250
    }
    
}

extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return models.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: CollectionTableViewCell.id, for: indexPath) as! CollectionTableViewCell
        cell.configure(with: models)
        return cell
    }
    
}
```
7.CollectionTableViewCellの実装
ポイントは、このカスタムテーブルビューセルにコレクションビューが入るので、ここでコレクションビューのデリゲートなどを設定してあげます。
また、`Model`を`ViewController`から受け取ってコレクションビューに渡していることに注意してください。
`configure`で`collectionView.reloadData()`しないといけないことも注意が必要です。


```swift:CollectionTableViewCell
final class CollectionTableViewCell: UITableViewCell {
    
    static var toString: String {
        return String(describing: self)
    }
    static let id = CollectionTableViewCell.toString
    static func nib() -> UINib {
        return UINib(nibName: CollectionTableViewCell.toString, bundle: nil)
    }
    private var models = [Model]()

    @IBOutlet private weak var collectionView: UICollectionView!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(MyCollectionViewCell.nib(), forCellWithReuseIdentifier: MyCollectionViewCell.id)
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }
    
    func configure(with models: [Model]) {
        self.models = models
        collectionView.reloadData()
    }
    
}

extension CollectionTableViewCell: UICollectionViewDelegate {
    
}

extension CollectionTableViewCell: UICollectionViewDataSource {
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        models.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCollectionViewCell.id, for: indexPath) as! MyCollectionViewCell
        let model = models[indexPath.row]
        cell.configure(with: model)
        return cell
    }
    
}

extension CollectionTableViewCell: UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 250, height: 250)
    }
    
}
```

8.MyCollectionViewCellの実装
`CollectionTableViewCell`から受け取ったモデルの情報を`UIImage`と`UILabel`に反映します。

```swift:MyCollectionViewCell
final class MyCollectionViewCell: UICollectionViewCell {
    
    static var toString: String {
        return String(describing: self)
    }
    static let id = MyCollectionViewCell.toString
    static func nib() -> UINib {
        return UINib(nibName: MyCollectionViewCell.toString, bundle: nil)
    }
    
    @IBOutlet private weak var myImageView: UIImageView!
    @IBOutlet private weak var myLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }

    func configure(with model: Model) {
        myImageView.image = UIImage(named: model.imageName)
        myLabel.text = model.text
    }
    
}
```

#おわりに
さらにこのなかにTableViewを入れてそのなかに、、、