[iOS 10] 全てのスクロールビューでRefresh Controlがサポートされました

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは! 加藤潤です。
iOS 10で全てのスクロールビューでRefresh Controlがサポートされました! 今回はこの機能をご紹介したいと思います。

Refresh Controlとは

まずはごく簡単にRefresh Controlについて説明します。
Refresh Controlとは、テーブルビューのUIでよくある「引っ張って更新」するためのUIコンポーネントで、UIKitのクラスはUIRefreshControlです。

refresh_control

iOS 9以前のUIRefreshControl

iOS 9までは、UIRefreshControlを生成し、UITableViewControllerrefreshControlプロパティにセットする形で使用していたかと思います。

class ViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        refreshControl = UIRefreshControl()
        refreshControl?.addTarget(self, action: #selector(ViewController.refresh(_:)), forControlEvents: .ValueChanged)
    }

    func refresh(sender: UIRefreshControl) {
        // ここに通信処理などデータフェッチの処理を書く
        // データフェッチが終わったらUIRefreshControl.endRefreshing()を呼ぶ必要がある
    }
}

UIRefreshControlのクラスリファレンスを見ると、「Because the refresh control is specifically designed for use in a table view that's managed by a table view controller, using it in a different context can result in undefined behavior.」と記載されています。 実装についてWebを検索すると、UITableViewControllerを使わずにUIViewControllerで管理するUITableViewにUIRefreshControlをaddSubviewして使用する例が散見されますが、動作が保証されていないのでこれはやらない方が無難かと思います。

iOS 10以降のUIRefreshControl

iOS 10ではiOS 9までの方法も使えますが、以下のようにUIScrollViewのプロパティとしてrefreshControlが追加されました。

@available(iOS 2.0, *)
open class UIScrollView : UIView, NSCoding {

    ・・・省略

    @available(iOS 10.0, *)
    open var refreshControl: UIRefreshControl?
}

UIViewControllerが管理するUITableViewでUIRefreshControlを使用する

UIScrollViewに追加されたrefreshControlプロパティを利用すればUITableViewControllerを使わずにUIRefreshControlが使えます。
以下はUIViewControllerが管理するUITableViewUIRefreshControlを使用する例です。

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    private let refreshControl = UIRefreshControl()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.refreshControl = refreshControl
        refreshControl.addTarget(self, action: #selector(ViewController.refresh(sender:)), for: .valueChanged)
    }

    func refresh(sender: UIRefreshControl) {
        // ここに通信処理などデータフェッチの処理を書く
        // データフェッチが終わったらUIRefreshControl.endRefreshing()を呼ぶ必要がある
    }
}

UICollectionViewでUIRefreshControlを使用する

もちろんUICollectionViewにも使えます。

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!

    private let refreshControl = UIRefreshControl()

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.refreshControl = refreshControl
        refreshControl.addTarget(self, action: #selector(ViewController.refresh(sender:)), for: .valueChanged)
    }

    func refresh(sender: UIRefreshControl) {
        // ここに通信処理などデータフェッチの処理を書く
        // データフェッチが終わったらUIRefreshControl.endRefreshing()を呼ぶ必要がある
    }
}

UIScrollViewでUIRefreshControlを使用する

もう説明は不要かと思いますが、当然UIScrollViewでも使えます。

class ViewController: UIViewController {

    @IBOutlet weak var scrollView: UIScrollView!

    private let refreshControl = UIRefreshControl()

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.refreshControl = refreshControl
        refreshControl.addTarget(self, action: #selector(ViewController.refresh(sender:)), for: .valueChanged)
    }

    func refresh(sender: UIRefreshControl) {
        // ここに通信処理などデータフェッチの処理を書く
        // データフェッチが終わったらUIRefreshControl.endRefreshing()を呼ぶ必要がある
    }
}

まとめ

UIScrollViewのプロパティとしてrefreshControlが追加されたことでUITableViewControllerに縛られずに使えるようになったことは嬉しいですね!

参考

UIRefreshControl Class Reference