なるようになるかも

力は多くの場合、その人の思いを超えない。

UISearchController を Rx で書けるように

iOS11 だと UISearchControllerUINavigationBar に入れられて楽しいので、入力した文字列をうまい感じで Observable<String> にしてくれる DelegateProxy を作ってみた。

UISearchResultUpdating+Rx の私的実装

なんで RxCocoa にないの?

PR 自体は何度か出てたけど蹴られてたっぽい。

./scripts/all-tests.sh 通してないなこの PR …。

ちゃんと RxSwift の作法っぽい感じで書き直したらこんな感じです。

これはちゃんと ./scripts/all-tests.sh も通ります。

よほどメジャーな delegate じゃない限り、この手のラッパーは各自で作ってねってスタンスだと思うので本家に PR は出さないですが。

UISearchController の使い方が分からない場合

ググってコードを探すよりも、Table Search with UISearchController というサンプルコードを見ると早いです。

なんと、Swift 版があるだけでなく、iOS11 対応済。

hidesSearchBarWhenScrolling が動作しない

UIScrollView と連動して動作してくれる条件は、以下の通り。

  • UIViewController の view が UIScrollView
  • UIViewController の view の subviews[0] が UIScrollView

Shrink large title when scrolling (not UITableViewController) iOS 11 に図解入りの超分かりやすい説明があります。

作った経緯とか

最初、UISearchResultsUpdating に準拠しなくても、searchController.searchBar.rx.value を subscribe すればいいんじゃ?と思ってたんですけれど、これだとうまくいかなかった。

  • キャンセル時に next が流れて来ない
  • 検索中に別の VC に push すると、ナビゲーションバーが消え去る

後者について、UISearchController が内部的に modal を出してるっぽいので、これを消すワークグラウンドとかを思いついたのですけれど、正規の方法で実装した方がよさそうだなぁということで素直に実装しましたとさ。

ついでだったので、SearchBar に入力したテキストを取れる Observable を追加したのですけれど、ちゃんと動いてるっぽい。

var queryText: Observable<String> {
    return Observable.merge(Observable.just(""),
                            RxSearchResultUpdatingProxy.proxy(for: base).didUpdateSearchResultSubject.map { $0.searchBar.text ?? "" })
        .distinctUntilChanged()
}

空文字と merge しているのは、combineLatest でフィルタリングしている実装の都合上です。