【Swift】tableViewとtableViewCellの使い方とソースコード事例

2018年8月3日

SwiftのUITableViewはテーブルを表示するクラスです。ちなみにUIScrollViewクラスを継承しています。

今日はソースコード上でのUITableViewとその中のセルを扱うUITableViewCellクラスの使い方を整理しています。

UITableViewの宣言の仕方とインスタンス生成

まず宣言は以下のように記述。

var myTalbeView:  UITableView!

リファレンスを見ると以下のようにinitメソッドが用意されている。

public init(frame: CGRect, style: UITableViewStyle)

引数のframeはCGRectオブジェクトで指定、
UITableViewStyleは
・UITableViewStyle.plain
・UITableViewStyle.grouped
の2つがあるのでどちらか設定する。

初期化は例えば以下のようにやる。

myTableView = UITableView(frame: self.view.frame, style: UITableViewStyle.grouped)

スタイルの見た目の違いは以下のような感じ。


UITableViewクラスのプロパティはたくさんある。。たくさんありすぎるので全部書かない。詳細はリファレンス参照。

rowHeight: CGFloat
sectionHeaderHeight: CGFloat
sectionFooterHeight: CGFloat
estimatedRowHeight: CGFloat
stimatedSectionHeaderHeight: CGFloat

◆TableViewの境界線を指定できる

UITableViewのseparatorStyleプロパティには、UITableViewCellSeparatorStyle.none または UITableViewCellSeparatorStyle.singleLine(デフォルト)を入れる。separatorColorにはUIColorの色を指定できる。

//事例
myTableView1.separatorStyle = UITableViewCellSeparatorStyle.none
myTableView1.separatorColor = UIColor.red

TableViewとTableViewCellの使い方

ここからが重要なポイント。TableViewクラスを使うには一連の流れがあり、そのとおり実装していくことになる。

①ViewControlerにデリゲートメソッドを2個記述

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

これでTalbeViewに関連するイベントを取得したり、値の設定ができるようになる。

②TableViewのインスタンスを生成して

var myTalbeView:  UITableView!

③デリゲートを設定

myTableView.delegate = self
myTableView.dataSource = self

④テーブルや中に配置するセルを定義する各種メソッドを定義

以下のメソッドがUITableViewDelegate, UITableViewDataSourceクラスにあるのでオーバーライドで上書きして再定義する。

  1. テーブル内のセクション数を決めるメソッド

    func numberOfSections(in tableView: UITableView) -> Int {}

  2. セクション内のセル数を決めるメソッド・・・★必須

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {}

  3. セルのインスタンスを生成するメソッド・・・★必須

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}

  4. セルの高さを決めるメソッド

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

  5. セクションのタイトルを設定するメソッド

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {}

  6. セクションの高さを設定するメソッド

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {}

この中で必須なのは★必須をつけている。他のメソッドは記述しなければデフォルト値が使われる。

詳しく見ていく。

1.テーブル内のセクション数を決めるメソッド

//事例
func numberOfSections(in tableView: UITableView) -> Int {
	return 2
}

このようにInt型で数字を返してあげると、それがセクション数になる。TableViewにおいて「セクション」と「セル」は重要なので覚えておきたい。セクションとセルは以下のようになっている。

2.セクション内のセル数を決めるメソッド・・・★必須

//事例
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
	return 3
}

このようにInt型で数字を返してあげると、それがセル数になる。セクションの中に何個のセル(行)を入れるかを設定できる。例えばメニューを3つ作りたいと思えば

let menus: [String] = ["メニュー1", "メニュー2", "メニュー3"]

などとして、return menus.countとやるようなイメージ。そうするとメニューの数だけセル(行数)を確保できる。

第2引数のsectionには現在のセクション番号が来る。numberOfRowsInSectionは引数のラベル。たぶんシステム内部の呼び出し側で使われている。このメソッド内では引数はsectionという変数名で使えば良い。

sectionは0から始まる(0,1,2…という)番号が振られている。

セクション0はセルが3つ、セクション1はセルが4つなど指定する場合はif文かswitchでセル数を返すことになるかもしれない。

3.セルのインスタンスを生成するメソッド・・・★必須

ここが重要です。このメソッドの中でセルを生成していきまいす。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}

ここで一旦セル(UITableViewCell)を調べていきます。

リファレンスを見ると初期化メソッドは以下のようになっている。

public init(style: UITableViewCellStyle, reuseIdentifier: String?)

第1引数のstyleではセルのスタイルを指定できる。以下の4つから選択して指定すること。
UITableViewCellStyle.default
UITableViewCellStyle.subtitle
UITableViewCellStyle.value1
UITableViewCellStyle.value2

セルの見た目は以下のように変わる。

第2引数のreuseIdentifierは再利用識別子と訳すことができる。何を指定するかわからないがString型なので適当な文字列を入れておけば良いと思う。

初期化は次のようにやる。

//事例
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "aaa")

UITableViewCellには以下のプロパティがある。

var textLabel: UILabel?
var detailTextLabel: UILabel?
var imageView: UIImageView?

それぞれに値をセットして使うことになる。

cell.textLabel?.text = string
cell.detailTextLabel?.text = string
cell.imageView?.image = UIImage(name: “dog.png”)

のようにして設定する。上の画像のようにtextLabel、detailTextLabel、imageViewが表示される。

これでセルを生成できるようになった。

なのでこのメソッドは

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}

以下のように使えばよく、TableViewにTableViewCell(1行)を追加できる。

//事例
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
	let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "aaa")
	cell.textLabel?.text = "ラベルだよ"
	cell.detailTextLabel?.text = "詳細なメッセージだよ
	cell.imageView?.image = UIImage(name: “dog.png”)
}

第2引数のcellForRowAtは第2引数のラベルなのでここでは(開発者は)使わない。このメソッド内ではindexPath変数を使う。
indexPathには以下の値が入っている。

indexPath.section → 現在のセクション番号(0、1、2‥)
indexPath.row → 現在の行番号(0、1、2‥)

この変数を使って、セクション○番の○行目のcellに何を記述するかを決める感じになる。

4.セルの高さを決めるメソッド

//事例
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
	return CGFloat(100)
}

CGFloat型でセルの高さを返せば設定される。

このメソッドを使うとindexPathには前述の現在のセクション番号と行番号が入ってくるので、1個1個のセルに対して高さを設定できる。

tableView.rowHeightでもセルの高さを指定できるが、rowHeightは全部のセルの高さを一律に決めるので使い分けできる。

5.セクションのタイトルを設定するメソッド

//事例
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
	return "第\(section)セクション"
}

こうすると1番目のセクションだったら、「第1セクション」というタイトルが設定される。

6.セクションの高さを設定するメソッド

//事例
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
	return CGFloat(50)
}

これもCGFloat型でセクションの高さを設定できる。

必要に応じてこれらのメソッドをオーバーライドして定義すれば、TableViewを構成することができる。

◆ソース全文

//事例
import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { // ‥①
    var myTableView1: UITableView!
    let textArry: [String] = [
    "1番めのセル","2番めのセル",
    "3番めのセルは長い文字列を設定して、\nセルの高さが自動的に調節されるようになるかを確認しようと思います。",
    "4番目のセル","5番目のセル"]

    override func viewDidLoad() {
        super.viewDidLoad()

        myTableView1 = UITableView(frame: self.view.frame, style: UITableViewStyle.grouped) // ‥②
        myTableView1.delegate = self // ‥③
        myTableView1.dataSource = self // ‥③
        myTableView1.estimatedRowHeight = 100
        myTableView1.rowHeight = UITableViewAutomaticDimension
        self.view.addSubview(myTableView1)
    }
    
    //④セクション数を指定
    func numberOfSections(in tableView: UITableView) -> Int {
        print("セクション数:1")
        return 1
    }
    //④セクションタイトルを指定
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "第\(section)セクション"
    }
	//④セル数を指定
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("セル数:5")
        return 5
    }
    //④セルを生成
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("セルの値を入れていく")
        let cell = UITableViewCell(style: UITableViewCellStyle.subtitle,
                                   reuseIdentifier: "aaa\(indexPath.section)-\(indexPath.row)")
        cell.textLabel?.text = "セクション番号 : \(indexPath.section)"
        cell.detailTextLabel?.text = "行番号 : \(indexPath.row)"
        //cell.detailTextLabel?.numberOfLines = 0
        //cell.detailTextLabel?.text = textArry[indexPath.row]
        cell.imageView?.image = UIImage(named: "dog2.png")
        return cell
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

TableViewのその他のメソッド

セルを選択したときのイベントを処理する

以下のメソッドもUITableViewDelateに用意されているのでオーバーライドして定義すれば、セルが選択された時にこのメソッドが動くようになる。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
	print("第\(indexPath.section)セクションの\(indexPath.row)番セルが選択されました")
}

TableViewをリロードするメソッド

myTableView1.reloadData()

とすればTableViewをリロードできる。テーブル内のどこかを編集した場合の後などにこのメソッドをよんでテーブルの再描画をしてもらう。

この他にメソッドがいくつかある。

例えば
tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
他にもいっぱいあるので割愛。

一律でテーブルのセルの高さを自動調整にする方法

セル内のUILabelの文字数が多かったりした場合に備えて、セルの高さも自動的に調整してくれる方が良い場合がある。

そのために以下のプロパティを設定する。

tableView.estimatedRowHeight
tableView.rowHeight

//使い方
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension

1行目は推定のセル高さをあらかじめ指定しておくことでTableViewのロード時間が早くなるのでこれをやると良いとされている。テーブルの高さが可変の場合は高さを計算するのに時間がかかるので、ここで推定高さを指定すると良い。

次に2行目は指定されたディメンションのデフォルト値を使用(意味はわからない)が、こうするとテーブルのセルの高さが自動的に調節される。

そしてセルの中のUILabelについても行数を可変にする処理を入れる。

//使い方
cell.detailTextLabel?.numberOfLines = 0
cell.detailTextLabel?.text = "長い長~い文字列、スマホの横画面をはみ出して折り返したり改行が入ったりするような長い文字列。"

セルを生成するときに中に表示する詳細のラベルの行数を無制限(0)にしておいて、textプロパティに文字列を代入します。

以下のようになる。(クリック拡大)

tableViewメソッドが呼ばれるタイミングを理解

気になるのはこれらのtableViewメソッドがいつ呼ばれているか。print文でそれぞれのメソッドに出力をしておけば理解ができる。
どのタイミングで呼ばれるかを知ることがUITableViewを理解する助けになる。

self.view.addSubview(myTableView1)

myTableView1.reloadData()
が実行された後。

numberOfSectionsメソッドが呼ばれてセクション数を指定して

tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)が呼ばれてセル数を指定して

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCellが呼ばれて
すべての行数(すべてのindexPath.sectionのindexPath.rowの数)だけ呼ばれる。
行数が3個あれば3回よばれる。indexPath.rowをprintすれば0, 1, 2と表示されるので。

こんな感じで自動的に呼ばれていってるのが実験でわかった。