iOS アプリ
スマートフォンの牽引役であった iPhone 3G が発売されてから既に10年以上経過しており、今では生活の一部になっています。これまで様々な iOS アプリがリリースされましたが、アプリの UI についても年々進化しています。主には Apple が推奨した方法が一般に展開されていることが多いですが、多くの開発者が利用している実装を Apple が標準として取り込むこともあります。今回紹介する「スクロールビューにおいて画面更新」についても、多くの開発者が使っている UI を Apple が標準として採用したものになります。
具体的には、画面に表示されている情報を最新にするために、画面を下にスワイプするとインジケータが表示され、画面の情報が最新になるとインジケータが消えるものになります。
一昔前の実装方法
iOS9 までは、自前で用意したりサードパーティ製のプラグインを利用したりしていました。自前で用意する場合、スクロールビューではコンテントビューの上部にインジケータ用の余白を持たせる実装を行ったり、テーブルビューでは最上部のセルにインジケータのみを設置し2つめのセルからを表示するような実装を行っていました。そのため、これらの制御が必要であり大きな手間になっていました。現在の実装方法
iOS10 より UIRefreshControl を利用できるようになりました。これは UIScrollView, UITableView, UICollectionView で利用することができます。上記コントローラには refreshControl プロパティが用意されているので、そこに UIRefreshControl クラスのインスタンスを渡すだけで利用できます。
また UIRefreshControl クラスのインスタンスに、インジケータが表示されたときの実行するメソッドを addTarget メソッドで追加します。
実際には、インジケータが表示されている間に何かを処理し、その処理が終わった後にインジケータを消すでしょう。そのときは UIRefreshControl クラスのインスタンスの endRefreshing() メソッドを呼び出せば大丈夫です。
具体的には次のようなソースコードになります。下記は UITableViewController クラスで利用しているので、先の説明と若干異なっていますが、基本的には同じ処理の流れになります。
import UIKit class ViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() //スクロールビューを下にスワイプした時の処理(インジケータ表示) refreshControl = UIRefreshControl() refreshControl?.addTarget(self, action: #selector(refresh), for: .valueChanged) } @objc func refresh() { //WebAPIを呼び出す(ここでは仮に2秒後に dataLoaded() を呼び出す) DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { self.dataLoaded() } } //WebAPIからレスポンスを受け取った後に呼び出すメソッド func dataLoaded() { //インジケータを隠す refreshControl?.endRefreshing() } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 10 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell") cell.textLabel?.text = String(indexPath.row) return cell } }