【Swift】Table View Controllerの使い方 その2。テーブルをビヨーンと引っ張って更新する。(Swift 2.1、XCode 7.2)
2020年6月16日
Refresh Controlとは
前回の記事でTable View Controller(以下、テーブルビューコントローラー)の基本的な使い方について説明した。⇒「記事」
その続きで、本記事ではテーブルビューコントローラーのプロパティにあるRefresh Control(以下、リフレッシュコントロール)について説明する。
リフレッシュコントロールとは、テーブルを下に引っ張ったときにActive Indicator Viewを表示する機能である。⇒「Active Indicator Viewとは」
ブラウザやTwitterで画面を下にビヨーンと伸ばしてページ更新したときに表示される読込中のあのマークだ。
リフレッシュコントロールを試す。
テーブルビューコントローラーはリフレッシュコントローラーを設定するためのプロパティ(refreshControl)を持っていて、そのプロパティにリフレッシュコントローラーのインスタンスを設定するだけで、テーブルビューを引っ張ったときに読込中マークが表示されるようになる。
そこでリフレッシュコントローラーを使って読込中マークを表示するものを作ってみよう。
以降の手順を開始する前のXcodeプロジェクトをGitHubに置いたので、実装を試してみる人はご利用されたし。
⇒「テスト用プロジェクト」
事前準備では、テーブルビューコントローラーのテーブルビューに苗字一覧が表示されるようにしておいた。この時点ではテーブルビューを下に引っ張っても何も起きない。これにリフレッシュコントローラーを追加して、待ち時間のあいだ読込中を表示するようにする。
リフレッシュコントロールは部品リストの中には無いのでソースコードから設定する。
TestTableViewController.swiftを以下のコードに変更する。
ViewDidLoadメソッドの中でリフレッシュコントロールをテーブルビューコントローラーに設定している。「テーブルビュー引っ張り時の呼び出しメソッド」で、レコードの半分を削除してテーブルビューの再読み込みを行っている。
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
// // TestTableViewController.swift // import UIKit class TestTableViewController: UITableViewController { //表示データ var dataList = ["佐藤","鈴木", "高橋","田中","渡辺","伊藤","山本","中村","小林","加藤","吉田","山田","佐々木","山口","松本","井上","斎藤","木村","林","清水","山崎","池田","阿部","森","橋本","山下","石川","中島"] //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //リフレッシュコントロールを作成する。 let refresh = UIRefreshControl() //インジケーターの下に表示する文字列を設定する。 refresh.attributedTitle = NSAttributedString(string: "読込中") //インジケーターの色を設定する。 refresh.tintColor = UIColor.blueColor() //テーブルビューを引っ張ったときの呼び出しメソッドを登録する。 refresh.addTarget(self, action: "refreshTable", forControlEvents: UIControlEvents.ValueChanged) //テーブルビューコントローラーのプロパティにリフレッシュコントロールを設定する。 self.refreshControl = refresh } //テーブルビュー引っ張り時の呼び出しメソッド func refreshTable(){ //配列に要素がある場合、要素の半分を削除する。 if(dataList.count > 0) { dataList.removeRange(0...dataList.count/2) } //読込中の表示を見るためにあえて2秒スリープする。 sleep(2) //テーブルを再読み込みする。 tableView.reloadData() //読込中の表示を消す。 refreshControl?.endRefreshing() } //データを返すメソッド override func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell { //セルを取得し、背景色と苗字を設定する。 let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath:indexPath) as UITableViewCell cell.backgroundColor = UIColor(red: CGFloat(drand48()+0.5), green: CGFloat(drand48()+0.5), blue: CGFloat(drand48()+0.5), alpha: 1.0) cell.textLabel?.text = dataList[indexPath.row] return cell } //データの個数を返すメソッド override func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int { return dataList.count } } |
以下は実際のプレイ動画
引っ張らずにインジケーターを表示する
テーブルビューを引っ張らずにインジケーターを表示することができる。では、画面左端をドラッグするとインジケーターが表示されるものを作ってみよう。
Screen Edge Pan Gesture Recognizer(以下、エッジリコグナイザー)を下図黄緑枠のTable Viewまでドラッグ&ドロップで運ぶ。すると紫枠のエッジリコグナイザーが追加されるので選択する。水色枠のアトリビュートインスペクタボタンを押して設定画面を表示し、Leftにチェックを入れる。
Ctrlキーを押しながら紫枠のエッジリコグナイザーをソースコードまで運んで吹き出しの設定画面を表示させる。Connectionに「Action」、Nameに「panLeftEdge」を入力し、Connectボタンを押す。これで画面左端をドラッグしたイベントをソースコードで受けれるようになった。
TestTableViewController.swiftを以下のコードに変更する。
画面左端のドラッグを開始したらbeginRefreshingメソッドを呼び出してインジケーターを表示する。この時、テーブルビューの位置を下にずらしてインジケーターを見えるようにしているのがポイントだ。
ドラッグが終了したら「テーブルビュー引っ張り時の呼び出しメソッド」を呼んでテーブルの更新を行っている。つまり、下に引っ張ったときと、左端をドラッグしたときで同じメソッドを呼び出してテーブルの更新をしている。
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
// // TestTableViewController.swift // import UIKit class TestTableViewController: UITableViewController { //表示データ var dataList = ["佐藤","鈴木", "高橋","田中","渡辺","伊藤","山本","中村","小林","加藤","吉田","山田","佐々木","山口","松本","井上","斎藤","木村","林","清水","山崎","池田","阿部","森","橋本","山下","石川","中島"] //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //リフレッシュコントロールを作成する。 let refresh = UIRefreshControl() //インジケーターの下に表示する文字列を設定する。 refresh.attributedTitle = NSAttributedString(string: "読込中") //インジケーターの色を設定する。 refresh.tintColor = UIColor.blueColor() //テーブルビューを引っ張ったときの呼び出しメソッドを登録する。 refresh.addTarget(self, action: "refreshTable", forControlEvents: UIControlEvents.ValueChanged) //テーブルビューコントローラーのプロパティにリフレッシュコントロールを設定する。 self.refreshControl = refresh } //画面左端ドラッグ時の呼び出しメソッド @IBAction func panLeftEdge(sender: UIScreenEdgePanGestureRecognizer) { if(sender.state == UIGestureRecognizerState.Began) { //ドラッグ開始時にインジケーターを表示する。 tableView.setContentOffset(CGPointMake(0, -refreshControl!.frame.size.height), animated:true) refreshControl!.beginRefreshing() } else if(sender.state == UIGestureRecognizerState.Ended) { //ドラッグ終了時にテーブルを更新する。 refreshTable() } } //テーブルビュー引っ張り時の呼び出しメソッド func refreshTable(){ //配列に要素がある場合、要素の半分を削除する。 if(dataList.count > 0) { dataList.removeRange(0...dataList.count/2) } //読込中の表示を見るためにあえて2秒スリープする。 sleep(2) //テーブルを再読み込みする。 tableView.reloadData() //読込中の表示を消す。 refreshControl?.endRefreshing() } //データを返すメソッド override func tableView(tableView:UITableView, cellForRowAtIndexPath indexPath:NSIndexPath) -> UITableViewCell { //セルを取得し、背景色と苗字を設定する。 let cell = tableView.dequeueReusableCellWithIdentifier("TestCell", forIndexPath:indexPath) as UITableViewCell cell.backgroundColor = UIColor(red: CGFloat(drand48()+0.5), green: CGFloat(drand48()+0.5), blue: CGFloat(drand48()+0.5), alpha: 1.0) cell.textLabel?.text = dataList[indexPath.row] return cell } //データの個数を返すメソッド override func tableView(tableView:UITableView, numberOfRowsInSection section:Int) -> Int { return dataList.count } } |
以下は実際のプレイ動画。左端をドラッグしたときは「読込中」の文字列が表示されないのが残念だ(Swift 2.1、XCode 7.2)。
文字列を設定するときの注意点
インジケーターの文字列を設定するタイミングには注意が必要だ。
以下のコードのように、テーブルビューコントローラーのrefreshControlプロパティにリフレッシュコントロールのインスタンスを設定したあとに文字列を設定すると、レコードの数が少ない状況ではアプリ起動時にいきなりインジケーターの文字列が表示る事象が発生する(Swift 2.1、XCode 7.2)。
バグが解消されるまではrefreshControlプロパティにリフレッシュコントロールのインスタンスを設定するようにしよう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //テーブルビューコントローラーのプロパティにリフレッシュコントロールを設定する。 self.refreshControl = UIRefreshControl() //インジケーターの下に表示する文字列を設定する。 refreshControl!.attributedTitle = NSAttributedString(string: "読込中") //インジケーターの色を設定する。 refreshControl!.tintColor = UIColor.blueColor() //テーブルビューを引っ張ったときの呼び出しメソッドを登録する。 refreshControl!.addTarget(self, action: "refreshTable", forControlEvents: UIControlEvents.ValueChanged) } |
以下は実際のプレイ動画。最初から「読込中」が表示されてしまっている。
テーブルビューコントローラー以外でも使える
リフレッシュコントロールはテーブルビューコントローラーだけでなく、UIWebViewやUIColloctionViewや普通のUITableViewなどビヨーンと引っ張れる部品にaddSubViewでリフレッシュコントロールの機能を追加できる。
以下はUITableViewにリフレッシュコントロールを追加したプレイ動画