UIKit ~UITableView~ 編

はじめに

UIButtonなどとは違い、UIKitの少し設定が面倒なUIを紹介していきます。

今回はUITableViewについて説明します。

UITableViewとは

UITableViewとはリスト表示をするためのUIです。
iOS標準の設定アプリをイメージするとわかりやすいかと思います。

このような1列のリストが連なっているものを表現するためのUIです。

実装方法

それでは早速実装方法について説明していきます。

新規プロジェクトを立ち上げて実装していきましょう。

Storyboard

まずMain.storyboardUITableViewを配置します。
ボタンなどと同様に以下のように検索しStoryboard上に配置します。

オートレイアウトを設定します。
今回は画面いっぱいに表示するので上下左右のマージンを0とします。
このUITableViewの領域にリストが表示されます。

これで表示領域が画面いっぱいに広がったかと思います。

次はUITableViewCellを配置します。
UITableViewCellとはリストに実際に表示する要素です。
以下のようなそれぞれ全ての要素がUITableViewCellで構成されています。
表示領域全体がUITableView、表示される要素がUITableViewCellというイメージです。

それではセルを配置します。
StoryboardでUITableViewを選択し、Attributes Inspectorを表示します。

Attributes Inspectorの一番上に[Prototype Cells]という項目があるのでこれを1に増やします。

1に設定するとStoryboard上にセルが1つ追加されます。

次にセルにIDを設定します。
追加されたUITableViewCellを選択しAttributes Inspectorの[Identifier]に任意のIDを設定してください。
以下の例ではSampleCellと設定しています。

これでStoryboardの設定は完了です。

ここで設定したセルはPrototypeというように、表示するセルの雛形です。
実際にはこの雛形を複製していき、複数のセルを表示していきます。

UITableViewをViewControllerに紐付ける

次はUITableViewをコードから操作できるようにViewControllerとアウトレット接続します。
接続の方法はボタンやラベルと同様です。

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

表示するセルを設定する

それでは表示するセルを設定していきます。

表示するセルの設定はDelegateDataSourceを使って設定します。
Delegateについてはこちらで簡単に説明しています。(DataSourceも似たようなものです)
もしわからなければこういう風に設定するんだという理解で今は構いません。

まずViewControllerUITableViewDataSourceUITableViewDelegateを継承します。

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
}

すると以下のエラーが表示されます。
Type 'ViewController' does not conform to protocol 'UITableViewDataSource'

これはViewControllerUITableViewDataSourceを継承しているけど必要なプロトコルに準拠していませんというエラーです。

UITableViewDataSourceは以下2つのメソッドを必須としています。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

これら2つのメソッドを実装してあげます。

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
    }
}

これで先程のエラーは消えます。

これらのメソッドそれぞれの役割は以下になります。

  • func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    • 表示するセルの個数を設定する
  • func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    • 表示するセルのオブジェクトを設定する

UITableViewはこれらのDataSourceで与えられた情報を元に表示するレイアウトを決定します。

それぞれのメソッドで戻り値を返していないのでエラーが出ているかと思います。
以下のように編集しましょう。

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath)
    return cell
}

1つ目のメソッドでreturn 10としています。
表示するセルは10個というように設定しているということです。

2つ目のメソッドについて。
let cell = self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath)
先程Storyboardで作成したセルの雛形を元にIDを指定してオブジェクトを作成しています。
return cellで生成したセルオブジェクトを返し、実際に表示するセルオブジェクトを設定します。
表示するセルは10個と設定しているのでこのメソッドは10回呼ばれます。
※正確には若干違いますが。

これで表示するセルの設定は完了です。

最後にUITableViewDelegateDataSourceViewControllerを紐付けます。

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.tableView.delegate = self
    self.tableView.dataSource = self
}

ここがDelegateを理解できていなければわからないかと思います。
やっていることはこちらで説明している4行目のbutton.delegate = hogeと同じです。
わからなければ今のうちは必ずviewDidLoadUITableViewにこのように設定すると覚えておいてください。

これでUITableViewの設定は完了です。
念の為ここまでのコードの全文を載せておきます。

import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath)
        return cell
    }
}

この状態で実行してみましょう。

リストが表示されました。
10個以上表示されているように見えますが実際には10個のセルが表示されています。
それぞれタップしていくと色が変わるのでわかりますが、11個目からは色が変わりません。

ここまでが最も基本的なUITableViewの表示の仕方です。

セルの表示を編集する

これだけではセルに表示も何もされていないのであまり意味がありませんね。

セルに文字を表示させてみましょう。

Main.storyboardを開いてください。

セルを選択しAttributes Inspectorの項目[Style]を[Basic]に変更してください。

ViewController.swiftを編集します。
以下のように変更します。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath)
    
    cell.textLabel?.text = "サンプルセル"
    
    return cell
}

この状態で実行します。

セルに文言が表示されました。

このようにセルの表示内容を設定するときは
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
でセルを取得できるのでその中で更新してあげます。

UITableViewCellにはデフォルトでBasic、Right Detailなどのスタイルが定義されています。
それぞれのスタイルで設定するプロパティが異なるので調べてから使ってみてください。

セルを独自にカスタマイズする

セルの表示変更方法について説明しました。
UIKitで提供されているBasicなどのスタイルだけで表示したいレイアウトを実現できる場合はこれで問題ありません。
ですがTwitterのタイムラインなどを見るとわかるかと思いますが、実際のレイアウトは複雑でこれだけでは実現することはできません。
多くの場合、自分で独自のセルクラスを作って表示したいUIを配置しています。

この独自のセルクラスの作成方法について説明します。

セルクラスを作成する

SampleCell.swiftファイルを作成し、UITableViewCellを継承したSampleCellを作成します。

import UIKit

class SampleCell: UITableViewCell {
    
}

StoryboardのセルをSampleCellクラスにする

Main.storyboardを開いてください。

先程Basicに指定していたスタイルをCustomに戻します。

セルを選択し、Identity Inspectorから作成したSampleCellクラスを設定します。
(画面遷移のときに新しくViewControllerを作ったときと同じ要領です。)
これでこのセルはSampleCellクラスのオブジェクトとして振る舞うようになります。

セルのレイアウトを変更しSampleCellと接続する

セルにラベルを配置してみましょう。
セル上にラベルをドラッグすれば配置できます。

オートレイアウトでセルの中央にラベルが来るように設定しておきます。

次に配置したラベルとSampleCellクラスをアウトレット接続します。
これはViewControllerに接続した方法と同様で、SampleCellまで持っていくだけです。

class SampleCell: UITableViewCell {
    @IBOutlet weak var centerLabel: UILabel!
    
}

一旦ViewControllercell.textLabel?.text = "サンプルセル"という部分を削除します。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath)
    
    return cell
}

この状態で実行してみましょう。

先程配置したラベルがセルに表示されています。

セルのUIを外から操作する

このラベルの文言を変更できるようにします。

SampleCellを以下のように編集し、ラベル文言を変えるメソッドを定義します。
メソッド名は自分で定義するものなので何でも構いません。

class SampleCell: UITableViewCell {
    @IBOutlet weak var centerLabel: UILabel!
    
    func setup(with text: String) {
        self.centerLabel.text = text
    }
}

これでsetupメソッドを呼び出すとラベル文言が変わるようになりました。

ではViewControllerからラベル文言を設定してあげましょう。
ViewControllerを以下のように編集します。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) as! SampleCell
    
    cell.setup(with: "カスタムセル")
    
    return cell
}

この状態で実行してみてください。

セルの文言を変更することができました。

self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) as! SampleCell

これでSampleCellにキャストしています。
dequeueReusableCellの戻り値はUITableViewCellなのでSampleCellで定義したsetupを呼び出すにはキャストしてあげる必要があるためです。

cell.setup(with: "カスタムセル")

これで実際にラベルの文言を更新しています。

行毎にレイアウトを変える

今全てのセルに対して「カスタムセル」を設定しているため10個同じようなセルが表示されています。
これをセル番号毎に変更します。

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)の引数にindexPathというパラメータがあります。
これは現在描画処理を行っているセルの要素番号を持っています。
これを使って行ごとの処理を変更することができます。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = self.tableView.dequeueReusableCell(withIdentifier: "SampleCell", for: indexPath) as! SampleCell
    
    cell.setup(with: "カスタムセル\(indexPath.row)")
    
    return cell
}

要素番号が表示されるようになりました。

この例では単純に要素番号と文字列を結合して表示しただけですが、例えばif文などで処理を分岐させるなど色々考えられます。

このようにして各セルのレイアウトを変更します。

また今回の例ではラベル1つのみでしたが、複数のラベルやボタンなど画面と同じように全てのUIを自由に配置することができます。
色々試してみてください。

最後に

今回はUITableViewの簡単な実装方法について紹介しました。
Delegate、DataSourceなど少し難しい内容も出てきましたが、一旦これはこういうものとして先に進めることをおすすめします。
大事なのは何を設定しなければいけないのか、どうすればセルを操作できるのかという点です。
UITableViewはよく使うUIなので使用方法だけは押さえておきたいところです。

次回はUICollectionViewについて紹介します。
とはいえ基本的にはUITableViewと同じです。

今回の内容は以上です。

コメント

タイトルとURLをコピーしました