徒然エンジニアブログ

徒然エンジニアブログ

理系東大生がプログラミングを中心に様々なことについて情報発信していきます!

【Swift】カスタムセルを作ってTableViewで使う方法

UITabaleViewを使うとき最初のうちは用意されているデフォルトのCellで満足するかもしれませんが、徐々に自分なりのセルを作りたいとなってくると思います。
今回のそのようなときのためにカスタムセルの作り方を書きたいと思います。

カスタムセルを作れば、セルの中に画像を入れたり、テキストを好きな場所に作ったりできるようになります。

カスタムセルの作り方

今回はタスク管理アプリを作っていると仮定し、セルの左側にタスクの名称、左側にタスクの期限が来るセルを作っていきたいと思います。

まずファイルを作る

new Fileからcocoa touchを選択し、ClassをCustomTableViewCell、Subclass ofをUITableViewCellにします。
するとCustomTableViewCell.swiftというファイルができます。
ここに書きていきます。

コードを書いていく

分けてコードを貼るとわかりにくいと思うのでいきなりコードを全部あげようと思います。

class CustomTableViewCell: UITableViewCell {
    
    let nameLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 18)
        label.textColor = UIColor.black
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let timeLimitLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 13)
        label.textColor = UIColor.lightGray
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: .subtitle, reuseIdentifier: reuseIdentifier )
        addSubview(nameLabel)
        addSubview(timeLimitLabel)
        
        nameLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 20).isActive = true
        nameLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
        nameLabel.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 3/5).isActive = true
        nameLabel.heightAnchor.constraint(equalTo: self.heightAnchor).isActive = true
        
        timeLimitLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -20).isActive = true
        timeLimitLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
        timeLimitLabel.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/5).isActive = true
        timeLimitLabel.heightAnchor.constraint(equalTo: nameLabel.heightAnchor).isActive = true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setCell(name: String, timeLimit: String) {
        nameLabel.text = name
        timeLimitLabel.text = timeLimit
    }
}

今回は全てコードでラベルなどを作っています。
そしてinit(style: UITableViewCell.CellStyle, reuseIdentifier: String?)関数の中で制約をかけてレイアウトを作っています。
コードだけでs制約をつけていく方法については過去の記事で説明しているので参考にしてください。
turedureengineer.hatenablog.com


setCell関数に引数として名前などを与えることでコードをスッキリさせることができます。

TableViewからの呼び出し方

tableViewで使うセルを登録する

tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")

これで自分で作ったセルをcellという名前で使うように登録できました。

セルを実際にインスタンス化する

以下の関数を追加します。
今回はTask型の配列であるtasksの内容をcellの中身に入れていきます。
TaskクラスはnameとtimeLimitという二つのプロパティを持ちます。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! CustomTableViewCell
        cell.setCell(name: tasks[indexPath.row].name!, timeLimit: tasks[indexPath.row].timeLimit!)
        return cell
    }

dequeueReusableCellというものはセルを使い回す時に使われます。
例えばセルが10000行あるとすると一度にこれらを全て読み出すことは無駄です。
何故ならば実際に見えるのはそのうち10行ちょっとに過ぎないからです。

こうすることで処理を軽くできます。