カスタムCellを使ったUITableView実装テンプレート

もう8月も終わりですね。夏の北アルプス登山は最高なのですが、今年はまだ行けてなくてウズウズしてます⛰
お気持ちが高まって、先週テント泊の練習に行ってきました。テント、最高です🏕

さて本題ですが、タイトル通りです。 TableViewを実装するシーンがよくあるので、コピペで使えるようにテンプレを作ってみました。 Xibで用意したカスタムCellを表示します。

f:id:muchan611:20190824150311p:plain

ソースコードはこちら にあるので、気になった方は覗いてみてください。

実装内容を簡単に説明していきます。

UITableViewと制約追加

class CustomCellListViewController: UIViewController {
    private var sampleItems = [CustomCellItem]()
    private let tableView = UITableView(frame: .zero)
    
    override func viewDidLoad() {
        super.viewDidLoad()

        title = "CustomCellListViewController"
        
        view.addSubview(tableView)
        tableView.separatorStyle = .none
        tableView.delegate = self
        tableView.dataSource = self
        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        tableView.register(cellType: CustomCell.self)
        
        sampleItems = [
            CustomCellItem(date: "2019/01/01", title: "あいうえお"),
            CustomCellItem(date: "2019/01/02", title: "かきくけこ"),
            CustomCellItem(date: "2019/01/03", title: "さしすせそ")
        ]
    }
}

私は基本的に、UITableViewのframe をCGRect.zeroで初期化して、左右上下の制約を親のViewに合わせる形で実装しています。 そして セルの登録 tableView.register(cellType: CustomCell.self) ですが、Extensionを書いて記述量を少なくしています。

public func register(cellType: UITableViewCell.Type, bundle: Bundle? = nil) {
    let className = String(describing: cellType)
    let nib = UINib(nibName: className, bundle: bundle)
    register(nib, forCellReuseIdentifier: className)
}

Extensionはこちら

こうしておくと、楽チンで良いですよ〜〜

カスタムCellの実装

カスタムCellは、Xibを利用して実装しています。

f:id:muchan611:20190824152312p:plain

Xibの Custom Class に紐付けるClass(今回は CustomCell)を指定したのちに、ラベルなどの各コンポーネントをCustomCellクラスに紐付けていきます。

UITableViewDataSource, UITableViewDelegateに準拠する

Protocolに準拠する場合、私はよく、見通しをよくするために 対象ViewControllerのextension に書くようにしています。

extension CustomCellListViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sampleItems.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = sampleItems[indexPath.row]
        let cell = tableView.dequeueReusableCell(with: CustomCell.self, for: indexPath)
        cell.update(item: item)
        return cell
    }
}

ここの dequeueReusableCell(with: CustomCell.self, for: indexPath) も、UITableViewのExtensionを書いて記述量を少なくしています。

public func dequeueReusableCell<T: UITableViewCell>(with type: T.Type,
                                                    for indexPath: IndexPath) -> T {
    let className = String(describing: type)
    let cell = dequeueReusableCell(withIdentifier: className, for: indexPath) as? T
    guard let dequeueCell = cell else {
        fatalError("Could not dequeue a cell of class \(className)")
    }
    return dequeueCell
}

Extensionはこちら

そして、UITableViewDelegateはこんな感じ。

extension CustomCellListViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let viewController = UIViewController()
        viewController.view.backgroundColor = .white
        navigationController?.pushViewController(viewController, animated: true)
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

セルをタップした際は、次の画面に遷移するようにします。 戻ってきたときに、セルがグレー(選択状態)になってしまうのが格好悪いので tableView.deselectRow(at: indexPath, animated: true) で選択状態を解除します。

以上、わたしのUITableView実装テンプレートの説明でした。 こういった、自分なりのテンプレートを用意しておくと、新しい画面の実装スピードも早くなって、良いですね〜🤸🏼‍♂️✨

ではでは、残りの夏も楽しみましょ〜🍧
ウー早く北アルプス行きたい...!!⛰⛰