UITableViewController 以外で UIRefreshControl を使う方法 [リスクあり]

Tweetie で有名になった Pull to refresh ですが iOS 6 から UIRefreshControl として OS 標準で追加されました。残念ながら UIRefreshControlUITableViewController と一緒に使うしかまっとうな方法はありません。UIViewController + UITableView のような構成で無理矢理使う方法を書いてみます。

重要

個人的におすすめしません。素直に UITableViewController で使うような方向でまず実装を検討してください。これから紹介する方法は OS バージョン等の要因に左右されて期待するような動きをしない危険性があります。

方法

UIRefreshControl を生成して UITableViewインスタンスに addSubview するだけです。

ただし、これだけではアプリが Background から Foreground に戻ってきた時やタブの切り替え等で viewWillAppear などが呼ばれたあとに UIRefreshControlUITableView よりも前面に出てくることがあります。

最前面に出てくるのをねじ伏せる方法

viewWillAppear で

[self fixRefreshControlLayout];
if (self.refreshControl.isRefreshing) {
    [self.tableView setContentOffset:self.scrollOffsetToRestore animated:NO];
}

というような感じにします。

  • 1行目で UIRefreshControl のレイアウトを調整
  • 2行目以降で refreshing 状態の時のために保持しておいた UITableViewcontentOffset を復元させています。

1行目の fixRefreshControlLayout はこんな感じ。

- (void)fixRefreshControlLayout
{
    if ([self isViewLoaded] == NO) {
        return ;
    }

    BOOL isRefreshing = self.refreshControl.isRefreshing;
    if (isRefreshing) {
        [self.refreshControl endRefreshing];
    }
    [self.refreshControl removeFromSuperview];
    self.refreshControl = nil;
    [self.tableView addSubview:self.refreshControl];
    if (isRefreshing) {
        [self.refreshControl beginRefreshing];
    }
}

最前面に出てきても再度 addSubview すれば期待する位置に出てきてくれるので念のため都度都度張り直しをしています。特にパフォーマンス上は大きな足かせにはなっていない印象です。

self.scrollOffsetToRestoreviewWillDisappear: のタイミングで現在の contentOffset を保持しておくようにしています。

まとめ

このような無理矢理な実装をしてねじ伏せるような実装を追加してもそんなに綺麗な感じじゃないです。ですので繰り返しになりますが素直な実装をとることを激しくおすすめします。Apple にはバグレポを通じて UIRefreshControlUITableViewController に限定されずに使えるように要望しましょう。