1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UIViewとUITableCellの共通化

Last updated at Posted at 2021-10-26

はじめに

こんにちは。
今回は、私がTableViewを使うプロジェクトでよく使っている、UIViewUIViewCellの共通化について書きます。
UIViewUIViewCellで同じようなデザインを使うことが多くて、この方法を見つけたときは感動しました。
TableViewがあるプロジェクトでは、ほぼ必ず使ってます。

ViewとCellの共通化が有効な場面

  • UITableViewのヘッダーにテーブルの項目タイトルをつけたい時
  • 通常はViewとして使う部品をTableViewのCellとしても利用したい

実装

仕組み作り

こんな感じで、プロトコルを1つ作ります。
CellとViewで共通利用したいカスタムビューにこのプロトコルを継承させればOKです。

extensionに定義したidentifierは、Cellをインスタンス化するときに使えるので、実装しておきます。

public protocol CellViewBinder {
    associatedtype ContentView: UIView
    static func contentView() -> ContentView
    static var identifier: String { get }
}

extension CellViewBinder {
    static var identifier: String {
        return String(describing: self)
    }
}

こっちがUIViewを継承したカスタムビューをUICellとして利用するために作るクラスです。

class GenericTableViewCell<View>: UITableViewCell where View: CellViewBinder, View.ContentView == View {

    let customView: View = .init(frame: .zero)

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        configure()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)

        configure()
    }

    private func configure() {
        contentView.addSubview(customView)

        customView.translatesAutoresizingMaskIntoConstraints = false
        customView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        customView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        customView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        customView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
    }
}

customView に自分の使いたいカスタムビューが入る構造です。
CellViewBinderプロトコルを継承しているカスタムビューだけが、GenericTableViewCellにビューを突っ込めるという仕様ですね。やはりプロトコル優秀すぎる。

実際に使う時


// Viewで使う時(例えばTableのヘッダーなどで)
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    return CustomView()
}

// Cellで使う時
guard let cell = tableView.dequeueReusableCell(withIdentifier: CustomView.identifier) as? GenericTableViewCell<CustomView> else {
    return UITableViewCell()
}
// 実際のViewにアクセスするのは、customView経由
let customView = cell.customView

参考文献

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?