初めてでも分かる!カスタムセルをSwiftで使用する方法
こんにちは、プログラマーの@Yuuです。
今回は「カスタムセル」の使い方を書きます。「カスタムセル」はアプリを作る中で様々な場面で使えます。覚える事で表現の幅も増え、きっと友達も増えます!
と冗談はさておき「カスタムセル」はとても便利なので、是非皆さんも覚えましょう!
今回の記事では以前に書いた「UITableViewの基本的な使い方」で解説したところは説明を多少簡略化しますので、分からないところがあればそちらの記事も参照しつつ読み進めて下さい。
スポンサーリンク
カスタムセルとは
まずは「UITableViewCell」の復習から。
iPhoneアプリを作っていると、情報をリスト化して表示したい事はよくあります。
そのような情報をリスト化して表示する時に使うのがUITableViewです。
そしてリスト化された情報のうちの1つを表示する領域を「セル」と言います。
iPhoneアプリでセルを表現するのが「UITableViewCell」というクラスです。
例えば以下のようなiPhoneの設定画面の場合、
「機内モード」「Wi-Fi」について表示しているそれぞれの領域を「セル」と言います。
「で、カスタムセルて何?普通にTableViewCellを使うのと何が違うの?」と言いますと、
そもそもTableViewCellをカスタムせずに使うと、出来る事が少ないんですね。
例えば以下のような事はカスタムセルを使わなくても表現出来ます。
ですが、画像を表示してテキストも表示してボタンも表示して・・みたいな事をやろうとすると、
カスタムセルを使わないといけません。
グダグダ説明を読むより、ここから下の作り方をやることで
「あぁ、カスタムセル使うとこういうことが出来るのね」と、分かってくると思います(投げやり)
というわけで、作り方に早速移りましょう。
今回は以下のようなものを作ります。
カスタムセルで表示出来るようになることを優先するので、
今回もUITableViewの値がステータスバーと被ちゃってますが、気にせずいきますよー。
カスタムセルを使う
今回解説を行う環境
今回解説を行う環境です。
- OS:OS X El Capitan10.11.4
- Xcode:7.3
- Swift:2.2
今回やる事
今回やる事を先に列挙しちゃいます。
- 表示する内容を用意する
- UITableViewとUITableViewCellを配置・設定
- UITableViewCellをカスタマイズ
- カスタムセル用のクラスを用意
- カスタムセルに値を表示する
重要なのは「項目3・項目4」の「カスタムセルの表示周りの設定」を行う部分ですね。
後は「項目5」で説明するところも少し。
それ以外の項目は、普通にUITableViewを使うのとそこまで変わらないです。
プロジェクトを作成するところは解説を省略しますが「Single Application」で作成して下さい。
一応、僕はプロジェクト名を「CustomCellSample」としたので、同じ環境でやりたい人はプロジェクト名を揃えて作成して下さい。
1. 表示する内容を用意する
画像と表示する文章を用意します。
まず画像から。
1-1. 画像を用意する
画像はご自身でのご用意をお願いします。
僕は以下の画像をぱくたそさんより拝借させて頂きました。
どの子も可愛いですねー。(〃ω〃)
それぞれの画像のURLは
ボックスから顔だけだして下を見ているオス猫(スコティッシュフォールド)
になります。
1-2. 画像をプロジェクトに関連付ける
画像をプロジェクトで使えるようにします。
まず画像をプロジェクトフォルダにドラッグアンドドロップします。
この時に以下のように聞かれますが、
「Copy items if needed」にチェックを付けてFinishボタンを押して下さい。
こうすることで元のファイルを削除しても、プロジェクト内の画像は消えません。
ここまで行うと、以下のように指定することで画像を扱うことが出来るようになります。
1 2 |
let image1 = UIImage(named: "cat1.jpg") let image2 = UIImage(named: "dog1.jpg") |
1-3. セルに表示する変数を用意する
セルに表示するための変数を用意します。
ViewController.swiftに以下を追記します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/// 画像のファイル名 let imageNames = ["cat1.jpg", "cat2.jpg", "dog1.jpg", "dog2.jpg"] /// 画像のタイトル let imageTitles = ["ネコ1", "ネコ2", "イヌ1", "イヌ2"] /// 画像の説明 let imageDescriptions = [ "ボックスから顔だけだして下を見ているオス猫", "寝ころびながらじゃれる猫", "散歩中のポメラニアン", "お散歩中のワンちゃん" ] |
変数を用意する際の注意点は2つ。
1点目は、imageNames
という画像のファイル名を指定する変数には、ご自身で用意した画像のファイル名を指定して下さい。
画像のファイル名と違うと、画像が表示されません。
2点目は、imageNames
・imageTitles
・imageDescriptions
の3つの変数の要素数は必ず揃えるようにして下さい。
要素数が違うとエラーが起きる可能性大です。
今回は配列で表示する項目を用意しましたが、実際にアプリを作る際には、表示するクラス(Javaだと『Bean』と呼ばれるものですね)を用意し、そのクラスのオブジェクトを必要分セルに表示するということが多いです。
2. UITableViewとUITableViewCellを配置・設定
ここは以前書いたUITableViewの使い方とほぼ同じなので、少し簡単に書きます。
まずUITableViewをViewControllerに配置。
次に配置したUITableViewをViewControllerいっぱいに広げ、AutoLayoutを設定。
UITableViewの子要素になるようにUITableViewCellを配置。
UITableViewCellをViewControllerのコード内で使用出来るように「Ientifier」を設定します。
Identiferには「MyCell」と設定します。
最後にUITableViewにdelegateとdetaSourceをViewControllerに設定します。
delegateとdetaSourceと詳しい設定方法はUITableViewの基本的な使い方を参考にして下さい。
ここまででUITableViewとUITableViewCellの配置と設定は終了です。
3. UITableViewCellをカスタマイズ
ここからがセルをカスタマイズする重要なところです。
先ほど配置したUITableViewCellの内容を、自分が表示したい配置にstoryboard上で変更していきます。
今回は以下のように1つのセルに「画像・タイトル・説明」という形にしたいので、
UIImageView1つとUILabelを2つ使用します。
3-1. セルの高さを変更する
まず今のセルの高さだと高さが足りないので、セルの高さを変更します。
少し注意して欲しいところとして、セルの高さを変更するためには、UITableViewCellではなくUITableViewの方にセルの高さを設定します。
TableView -> Show the Size inspector -> Row Heightの値を変更します。
3-2. オブジェクトを配置する
UIImageViewとUILabel2つを配置します。
UIImageViewをUITableViewCellに配置します。
MyCellのContent Viewの子要素として、ImageViewとUILabel2つがあればOKです。
3-3. セルのオブジェクトのレイアウト設定を行う
今回はAutoLayoutを設定すると長くなりそうなので、
UIImageViewのX・Y・Width・Height、
UILabelのWidth・文字色・文字サイズの3つを変更します。
UIImageView
- X 8
- Y 8
- Width 144
- Height 100
上のUILabelを
- フォントサイズ 18
- 文字色 変更なし(Default)
- Width 424
下のUILabelを
- フォントサイズ 15
- 文字色 Dark Gray Color
- Width 424
に変更します。
AutoLayoutをきちんと設定していないので、表示が若干崩れることもあると思いますが、今回は表示出来る事に重きを置くので、最終的に表示されればOKです。
次は配置したオブジェクトに値を設定するために、UITableViewCellクラスを継承したCustomCellクラスを作成します。
継承と言われて「けいしょう・・?」となる人のために、少し噛み砕いて説明してみます。
UITableViewを使って表現する時には「セル」(UITableViewCell)というものを使わないといけない。
しかし普段使っているセルでは、画像やラベル2つを表現出来ないので、普段使っているセルを自分好みに変形させた「カスタムセル」というものを使う必要がある。
その「カスタムセル」を使うためには、普段使っているセルのクラス(UITableViewCellクラス)を変形させたカスタムセル用のクラス(今回は『CustomTableViewCell』クラスという名前にします)というものを用意しないといけない。
こんな感じで伝わるかな・・?
今は分からなくても、書いてるうちに段々分かるようになるので、今はとりあえず作ってみましょう!
4. カスタムセル用のクラスを用意
4-1. カスタムセル用のクラスを作成
ではカスタムセル用のクラスを作成します。
メニューバーからFile -> New -> File...の順に選択し新しいファイルを作成します。
出てきた画面から「Cocoa Touch Class」を選択しNEXTボタンを押します。
「Cocoa Touch Class」が見当たらない場合は、すぐ左にあるメニューバーのようなところからiOS -> Sourceと選択すると「Cocoa Touch Class」が選択出来ます。
次のクラス名を指定する画面で「Subclass of:」と書かれたところを「UITableViewCell」に変更し、「Class:」と書かれたところに「CustomTableViewCell」と入力し、NEXTボタンを押します。
次の画面ではそのままCreateボタンを押します。
すると以下のようなUITableViewCellクラスを継承したCustomTableViewCellクラスが作成されます。
1 2 3 4 5 |
class CustomTableViewCell: UITableViewCell { . // 省略 . } |
4-2. storyboardのオブジェクトを紐付ける
先ほど配置したUIImageViewやUILabelを、今作成したCustomTableViewCellクラスと紐付けます。
紐付けるためには、最初に配置したUITableViewCellを「CustomTableViewCell」クラスに変更する必要があります。
Main.storyboardを開き配置したUITableViewCellを選択し、
Show the Identity inspector-> Custom Class -> Classに
「CustomTableViewCell」と入力します。
この作業をすることで、storyboard上のUIImageViewなどをCustomTableViewCell.swiftのファイルと紐付ける事が出来ます。
次にツールバーから「Show the Assistant editor」ボタンをクリックし、storyboardとコードを紐付ける画面にします。
最初はCustomTableViewCell.swiftが右の画面に表示されていないはずなので、CustomTableViewCell.swiftにファイルを変更します。
以下の画像のように、左のstoryboard上でセルの中のオブジェクト(画像だとImage View)を選択した状態にすると、右側の画面の「Automatic」という項目から「CustomTableViewCell.swift」が選択出来るので便利ですよ。
UIImageViewとUILabel2つをIBOutletとしてCustomTableViewCell.swiftに紐付けます。
storyboardのオブジェクトとコードを紐付ける方法は、storyboardのオブジェクト上でcontrolボタンを押しながら、コードの方に持ってくると紐付ける事が出来ます。
僕は以下のような変数名で定義しました。
1 2 3 4 5 6 |
/// イメージを表示するImageView @IBOutlet weak var myImageView: UIImageView! /// タイトルを表示するLabel @IBOutlet weak var myTitleLabel: UILabel! /// 説明を表示するLabel @IBOutlet weak var myDescriptionLabel: UILabel! |
ここまで終わると以下の画像のようになっているかと思います。
さぁ!次からいよいよカスタムセルに値を表示する設定をしますよー。
5. カスタムセルに値を表示する
5-1. デリゲート・データソースメソッドを実装
UITableViewの基本的な使い方で書いた時と同じように、以下のようにViewControllerクラスにUITableViewのdelegateとdetaSourceを実装します。
1 2 3 4 5 |
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { . // 省略 . } |
UITableViewDelegate, UITableViewDataSource
を実装するとエラーが起きます。
これは、UITableViewDelegate, UITableViewDataSource
を実装するにあたり必ず必要なメソッドをまだ書いていないからです。
というわけで、必要なメソッドを「とりあえず」ViewControllerクラスに追加します。
1 2 3 4 5 6 7 8 9 10 |
/// セルの個数を指定するデリゲートメソッド(必須) func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } /// セルに値を設定するデータソースメソッド(必須) func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { return UITableViewCell() } |
ここまではUITableViewの基本的な実装方法と一緒です。
今実装したメソッドはまだ「とりあえず書いただけ」の状態で、セルには何も表示されません。
一応ここまで書いたViewController.swiftの全文のコードを書いておきますね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { /// 画像のファイル名 let imageNames = ["cat1.jpg", "cat2.jpg", "dog1.jpg", "dog2.jpg"] /// 画像のタイトル let imageTitles = ["ネコ1", "ネコ2", "イヌ1", "イヌ2"] /// 画像の説明 let imageDescriptions = [ "ボックスから顔だけだして下を見ているオス猫", "寝ころびながらじゃれる猫", "散歩中のポメラニアン", "お散歩中のワンちゃん" ] override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /// セルの個数を指定するデリゲートメソッド(必須) func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 } /// セルに値を設定するデータソースメソッド(必須) func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { return UITableViewCell() } } |
5-2. カスタムセルに値を表示する
ここからカスタムセルに値が表示されるように設定していきます。
まず1番上のセルの個数を指定するデリゲートメソッドから。
今回は「用意している写真の数」が表示したいセルの数なので、以下のように書きます。
1 2 3 4 |
/// セルの個数を指定するデリゲートメソッド(必須) func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return imageNames.count } |
ここも普通にTableViewを使う際と変わりません。
カスタムセルを使う際に普通にTableViewを使う時と変わるのは、次に解説を行う「セルに値を設定するデータソースメソッド」です。
ではまずどのように書くかを先に提示しちゃいます。
1 2 3 4 5 6 7 8 9 10 11 12 |
/// セルに値を設定するデータソースメソッド(必須) func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // セルを取得 let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as! CustomTableViewCell // セルに値を設定 cell.myImageView.image = UIImage(named: imageNames[indexPath.row]) cell.myTitleLabel.text = imageTitles[indexPath.row] cell.myDescriptionLabel.text = imageDescriptions[indexPath.row] return cell } |
重要なところは4行目のlet cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as! CustomTableViewCell
です。
これをやることによって「ここで取得するセル(let cell
)は、自分で作ったCustomTableViewCellクラスだよ」とセルに覚え込ませます。
そうすることで、CustomTableViewCellに配置したUIImageViewやUILabelに値をセットする事が出来るようになります。
UIImageViewやUILabelに値をセットする事を実際にやっているのが、6~8行目です。
ここでセルに配置した画像やテキストに値を設定しています。
4行目で宣言した変数cell
がCustomTableViewCellクラスなので、
cell.myImageView
・cell.myTitleLabel
のような指定が出来るようになっているんですね。
これは先ほど自分で作成したCustomTableViewCellクラスに
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class CustomTableViewCell: UITableViewCell { /// イメージを表示するImageView @IBOutlet weak var myImageView: UIImageView! /// タイトルを表示するLabel @IBOutlet weak var myTitleLabel: UILabel! /// 説明を表示するLabel @IBOutlet weak var myDescriptionLabel: UILabel! . . //省略 . . } |
このように定義したからです。
では、ここまでやったら実行してみます!
すると以下のように・・
実行出来ましたー!
いえーい(๑•̀ㅂ•́)و✧
5-3. スマートにコーディングする
ただ、このままだと少しスマートじゃないところがあります。
カスタムセルを使うんだったら、もっとスマートに書こうぜ!
そう、カスタムセルならね。
・・。
一回言ってみたかったんです、すいません。
そんなことはおいといて「カスタムセルを使う時はこう書く」という定番のやり方があるので、そちらの方法を書いておきます。
まずCustomTableViewCellクラスに、メソッドを追記して全文を以下のようにします。
追加したのはマーカーで表示している25〜30行目です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import UIKit class CustomTableViewCell: UITableViewCell { /// イメージを表示するImageView @IBOutlet weak var myImageView: UIImageView! /// タイトルを表示するLabel @IBOutlet weak var myTitleLabel: UILabel! /// 説明を表示するLabel @IBOutlet weak var myDescriptionLabel: UILabel! 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 } /// 画像・タイトル・説明文を設定するメソッド func setCell(imageName: String, titleText: String, descriptionText: String) { myImageView.image = UIImage(named: imageName) myTitleLabel.text = titleText myDescriptionLabel.text = descriptionText } } |
次に先ほどの「セルに値を設定するデータソースメソッド」のを変更し以下のようにします。
1 2 3 4 5 6 7 8 9 10 |
/// セルに値を設定するデータソースメソッド(必須) func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // セルを取得 let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as! CustomTableViewCell // セルに値を設定 cell.setCell(imageNames[indexPath.row], titleText: imageTitles[indexPath.row], descriptionText: imageDescriptions[indexPath.row]) return cell } |
変更したのは7行目の部分。
ViewController.swiftでやっていたことを、CustomTableViewCellクラスの方に移動させただけ、ですね。
こうすることでViewController.swift側のコードは1行に変更する事が出来るので、可読性も上がります。
カスタムセルを使う場合、僕はいつもこのようにカスタムセルにsetCell("引数")
というメソッドを用意する方法で書いています。
色々な人のコードを見てもこのように書かれている事が多いので、こう書くのがベストなのかなぁと思ってsetCell("引数")
と書くようにしています。
長くなってしまいましたが、以下が今回のViewController.swiftの全文です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import UIKit class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { /// 画像のファイル名 let imageNames = ["cat1.jpg", "cat2.jpg", "dog1.jpg", "dog2.jpg"] /// 画像のタイトル let imageTitles = ["ネコ1", "ネコ2", "イヌ1", "イヌ2"] /// 画像の説明 let imageDescriptions = [ "ボックスから顔だけだして下を見ているオス猫", "寝ころびながらじゃれる猫", "散歩中のポメラニアン", "お散歩中のワンちゃん" ] override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } /// セルの個数を指定するデリゲートメソッド(必須) func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return imageNames.count } /// セルに値を設定するデータソースメソッド(必須) func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // セルを取得 let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as! CustomTableViewCell // セルに値を設定 cell.setCell(imageNames[indexPath.row], titleText: imageTitles[indexPath.row], descriptionText: imageDescriptions[indexPath.row]) return cell } } |
あとがき
カスタムセルはよく使うので解説してみました。
しかし、めちゃくちゃ長くなってしまいましたね・・。
ここまで読んで下さった方、ありがとうございます!
少しでも参考になれば幸いです。
GitHubに今回作ったプロジェクトのソースコードを上げておいたので、良かったら参考にして下さい。
meganedogYuu/CustomCellSample: カスタムセルの作り方のサンプルコード - GitHub
ではでは
今回はこの辺で!ヽ(•̀ω•́ )ゝ✧