anz blog

UIRefreshControlちゃんと導入できていますか?

2018-03-08 #Swift

若干あおりっぽいですが...(笑)
先日こちらのブログ記事をみていて、そういえばそんなプロパティも追加されてたっけ...
とふと思い、何か違うのかなぁ?ってちょちょっと検証してたら違ったのだけれど、それより大事なことを知ってしまったので

UIRefreshControl導入方法によって違う...ってか、え?これダメなの!?

です!(笑)

環境

  • Xcode v9.2
  • Swift v4.0

UIRefreshControlとは?

iOSでapp作ってりゃ説明いらないとおもいますが...
リスト系のやつで引っ張って更新っていう操作がよくあるけども
アレを実現してくれるやつです。

導入方法

2つ(?)紹介します

addSubview()で導入する(旧?バージョン)

むかーしから使われている方法ですね..。

let refreshControl = UIRefreshControl()
self.tableView.addSubview(refreshControl)

こういう感じ。
これで引っ張ることができるようになります。

refreshControlプロパティで追加する(新バージョン)

新バージョンっていってもこのプロパティが追加されたのはけっこう前なはず...(笑)

let refreshControl = UIRefreshControl()
self.tableView.refreshControl = refreshControl

こういう感じ。

この旧と新で一見すると同じ挙動になるので、
僕は「導入できる方法が2つあるだけでも何も変わらんだろう〜」ぐらいに思っていました。
が、それが特定の条件下だと挙動に差異がでてきます。

先に紹介したブログのほうで話題になっていたのですぐ気づいたのですが...
UINavigationBarがlargeTitleモードになっていると挙動が違ってきます。
くるくるが出て来るところが全然違う(笑)

旧バージョン

UIRefrechControl addSubview バージョン

引っ張ってる最中はなんか見えない(多分広がったNavigationBarに隠れている)で、
引っ張っている状態から戻ってきた時にやっとくるくるがみえる感じ

新バージョン

UIRefreshControl property バージョン

もうTableViewの領域を超えてNavigationBarのほうにでちゃう!
多分こっちが本来あるべき挙動だと思われます
もどってくるアニメーションもなんかスムーズですし。旧バージョンのほうはちょっと変な感じがするのです。

スクロールによるBounceが効かない(要らない)場合

ちょっと説明が難しいのですが...
例えば...

self.tableView.alwaysBounceVertical = false

という感じでbounceを無効にして、かつスクロールが発生しない状態(件数が0件だったり少数で画面内におさまる場合)...そういうケースです

旧バージョン

引っ張って更新ができません。ひっぱれません。

新バージョン

引っ張れます。いつものように引っ張って更新できます。

旧バージョンの場合、addSubview()なので、TableViewの状態に依存してしまいできないのでしょうか。。?
ただ、これは困った話で、仕様的にbounceいらね!ってなって、たまたま取得した件数が2件とか少数だった場合...もうリストを更新できなくなるっていうことなのです。
(bounceはいらんとは言ったが引っ張って更新までいらんとは言っていない!みたいな...?)


とりあえずこの2つのケースで挙動による差異がありましたが、
いずれもなんか新バージョンのほうが正しい挙動なような気がするので、
特別な理由がない限り新バージョンのほうで導入しておいたほうが良さそうですね。

追加したからにはそりゃ意味ありますよね😇
(そう意味はあるのです!)

というか旧バージョンはそもそもアカン!?

らしい(笑)

当初はUITableViewController前提でUIRefreshControlが導入されていて、
いやいやUIViewController + UITableViewという構成でも使いたいでしょっていうあれから生まれたハック的な手法っぽい?
新旧とかじゃなかった..正式か非公式かだ😇
そりゃ挙動ちがうし、refreshControlプロパティのほうが正しいですね!

UIScrollViewを継承している全てのViewでrefreshControlプロパティが有効になった今...
addSubview()でやる意味はなさそうですね。むしろ非推奨か。(iOS9以前でも対応するならやむなしかもですが)...

いまざっくりぐぐってみても新しい記事でもaddSubview()のほうもバンバン出てくるので根強く浸透しちゃってるなぁ...

参考

いろいろ検証するきっかけになりました🙏

昔はこちらのドキュメントに

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.

という注釈があったみたい。今は消えているけど
iOS10が出てScrollViewにrefreshControlプロパティが追加されたので、
UITableViewControllerを前提にしているわけじゃなくなったからでしょうね...