Rxでインタラクティブにロード中の表示を出す
Rxを使うと○○中というステータスをリアルタイムに取得できます。
ただデフォルトの機能としてビューをステータスに応じて表示/非表示などは備わっていません。
そこでこういうのは開発者自身が実装してやる必要があります。
既存のライブラリをRxで使いやすく
Rxの理念に準じてbindした先の値に応じて動作できるようなものを作成します。
例えばローディング中の表示としてよく使われるMBProgressHUDをRxでこんな風にします。
MBProgressHUD+RxSwift.swift
import UIKit
import MBProgressHUD
import RxSwift
import RxCocoa
extension Reactive where Base: MBProgressHUD {
static func isAnimating(view: UIView) -> AnyObserver<Bool> {
return AnyObserver { event in
switch event {
case .next(let value):
if value {
MBProgressHUD.showAdded(to: view, animated: true)
} else {
MBProgressHUD.hide(for: view, animated: true)
}
default:
break
}
}
}
}
これで MBProgressHUD はBool値を得たときに表示/非表示を行うようになります。内部的にはMBProgressHUD の showAdded / hide メソッドを切り替えるようにしているだけです。
ロード中に表示 / 終わったら非表示
あとはロード中のフラグとbindしてあげればOKです。
使い方の例はこんな感じです。
Sample.swift
/// ローディング中ならtrue
var isLoading: Variable<Bool> = Variable(false)
# 略
///APIのレスポンス取得
func fetch() -> Observable<SomeResponse> {
// RXSwift + APIKit を利用してAPIをコール
return SomeAPIRequest().asObservable().do(onNext: { responseData in
self.esponse.value = responseData
}, onError : { error in
print(error)
self.isLoading.value = false
}, onCompleted: {
self.isLoading.value = false
}, onSubscribed: {
self.isLoading.value = true
})
}
// ローディング
self.isLoading.asDriver()
.drive(MBProgressHUD.rx.isAnimating(view: self.view))
.disposed(by: rx.disposeBag)
isLoadingの値がtrueの場合にMBProgressHUDを表示し、falseになったら非表示にします。
表示されない場合などは MainScheduler.ensureExecutingOnScheduler() を入れるなどして調整してみてください。