TableViewで一番下まで行ったら次のページをロードする
この前、とある課題でニュースリーダーアプリ的なのを作った際、TableViewで一番下まで行ったら次のページをロードするのを実装しようとしたら、割とごちゃっとしてたので自分なりに整理しておきます。
インジケータが乗ったxibファイルを作る
下までスクロールしたときにくるくるしてるやつですね。
これをxibファイル作ってセルに配置して、TableViewにフッターとして埋め込みます。
// ArticleListViewController.swift override func viewDidLoad() { super.viewDidLoad() self.tableView.register(R.nib.loadingCell) let footerCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.loadingCell.identifier)! (footerCell as! LoadingCell).startAnimation() let footerView: UIView = footerCell.contentView tableView.tableFooterView = footerView }
一番下にたどりつく前に次のapiを叩く
一番下までスクロール仕切らないところでAPI叩いて、下までたどり着くときにちょうどParseが終わってるようにします。
(つまりさっきのインジケータが日の目を見るのはほんの一瞬)
// ArticleListViewController.swift func scrollViewDidScroll(_ scrollView: UIScrollView) { let currentOffsetY = scrollView.contentOffset.y let maximumOffset = scrollView.contentSize.height - scrollView.frame.height let distanceToBottom = maximumOffset - currentOffsetY if distanceToBottom < 500 && tableView.isDragging { self.viewModel?.search() } }
リクエスト調整
このままだと一回下までスクロールしたらそのままずっとAPI叩いちゃうので、Parseが終わるまでは次のリクエスト送らないように、以下のようなStatusを作ります。
enum LoadStatus { case initial case fetching case full }
最初は.initial
にしておいて、非同期処理の中で状態を設定し直してあげます。
// ArticleListViewModel.swift func search() { guard loadStatus == .initial else { return } self.loadStatus = .fetching self.shared.sync(query: self.searchWord, page: self.page) .subscribe { [weak self] result in switch result { case .success(let data): self?.articles.append(contentsOf: data.articles) if data.articles.count != 0 { self?.refreshToggle.accept(()) self?.page += 1 self?.loadStatus = .initial } else { self?.loadStatus = .full } case .error(let error): print(error) self?.loadStatus = .initial } }.disposed(by: disposeBag) }
QiitaのAPIだと、一回のリクエストでは最大100件までしか取得できないので、page
って変数に先に叩いたページ保存しておいて、一回リクエエスト叩くごとに増やしていくことで順番に取得していくことができます。
ソースコードの全貌載せておきます。
参考にした記事はこちら↓
少なくとも私がやった感じQiitaのAPIって割とすぐに403(リクエスト送りすぎ)って返って来ちゃうのでスクロールし過ぎには注意が要りそうです、、、汗
何か気になる所ありましたら是非教えて下さい〜!!