【Swift】伸縮するTableViewヘッダーを作成する




ツイッターのように画面を下にスクロールした際に、画像が拡大するヘッダーを実装する機会があったので備忘録として書きます！

##完成形
TableViewを下に引っ張った際に画像を拡大させる。

![currymov](https://user-images.githubusercontent.com/75295738/131461769-41f5116d-437e-41ed-8901-06aba620fa3a.gif)

##実装方法
AutoLayoutなど様々なやり方があると思いますが、今回はTableViewCellを使用した方法で実装していきます。

##①カスタムセルを用意する
適当なセルを用意してUIImgeViewをのせます。

```swift:StretchyHeaderTableViewCell.swift
import UIKit

final class StretchyHeaderTableViewCell: UITableViewCell {

    @IBOutlet weak var headerImageView: UIImageView!
    static var className: String {
        return String(describing: self)
    }

    static var idetifier: String {
        return className
    }

    static func nib() -> UINib {
        return UINib(nibName: idetifier, bundle: nil)
    }

    func configure(headerImageUrl: String) {
        headerImageView.image = UIImage(named: headerImageUrl)
    }
}
```

##②TableViewへ登録する
上記で作成したカスタムセルをtableviewへ登録します。
##③制約を加える

```swift:StretchyHeaderViewController.swift
private var lastContentOffset = CGPoint.zero
```

```swift:StretchyHeaderViewController.swift
extension StretchyHeaderViewController: UITableViewDelegate {

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.contentOffset.y <= 0.0 {
            if let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) {
                let deltaY = CGFloat(fabsf(Float(scrollView.contentOffset.y)) - fabsf(Float(lastContentOffset.y)))
                cell.frame = CGRect(x: 0.0, y: scrollView.contentOffset.y, width: cell.frame.size.width, height: cell.frame.size.height + deltaY)
                lastContentOffset = scrollView.contentOffset
            }
        }
    }
```

##全体のコード

```swift:StretchyHeaderViewController.swift

import UIKit

final class StretchyHeaderViewController: UIViewController {
    @IBOutlet private weak var tableView: UITableView!
    private var lastContentOffset = CGPoint.zero
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.tableFooterView = UIView()
        tableView.register(StretchyHeaderTableViewCell.nib(), forCellReuseIdentifier: StretchyHeaderTableViewCell.idetifier)
    }
}
extension StretchyHeaderViewController: UITableViewDelegate {

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.contentOffset.y <= 0.0 {
            if let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) {
                let deltaY = CGFloat(fabsf(Float(scrollView.contentOffset.y)) - fabsf(Float(lastContentOffset.y)))
                cell.frame = CGRect(x: 0.0, y: scrollView.contentOffset.y, width: cell.frame.size.width, height: cell.frame.size.height + deltaY)
                lastContentOffset = scrollView.contentOffset
            }
        }
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 200
    }
}

extension StretchyHeaderViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: StretchyHeaderTableViewCell.idetifier) as! StretchyHeaderTableViewCell
        cell.configure(headerImageUrl: "curry")
        return cell
    }
}
```

##最後に
一見難しそうですがたったこれだけでツイッターライクなヘッダーが完成します。最近のアプリだとスクロール時に画像が拡大するものが多いのでぜひ参考にしてください！