はじめに
Qiitaが提供しているAPIを使用して、TableView
に記事を表示する際に、データの__読込__・リフレッシュ・__更新__について実装しましたので備忘録として投稿します。
概要
-
QiitaAPI
の初期取得 - 取得している
QiitaAPI
のリフレッシュ -
TableView
下部までスクロールした際にQiitaAPI
追加取得
※上記にフォーカスをあたて説明になります。
動作環境
【Xcode】Version 12.0.1
【Swift】Version 5.3
実装コード
CustomTableView.swift
import UIKit
class CustomTableView: UITableView {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override init(frame:CGRect, style: UITableView.Style) {
super.init(frame: frame, style: .plain)
setup()
}
private func setup() {
let refreshControl = UIRefreshControl()
refreshControl.attributedTitle = NSAttributedString(string: "読み込み中")
self.refreshControl = refreshControl
// UITableViewが空のときの線(セパレーター)を消すために、空のViewを設定
self.tableFooterView = UIView()
}
func addTargetToRefreshControl(_ target: Any?, action: Selector, event: UIControl.Event) {
self.refreshControl?.addTarget(target, action: action, for: event)
}
func beginRefreshing() {
guard let refreshControl = self.refreshControl else { return }
refreshControl.beginRefreshing()
refreshControl.sendActions(for: .valueChanged)
self.contentOffset.y = -self.bounds.height
}
func endRefreshing() {
guard let refreshControl = self.refreshControl else { return }
refreshControl.endRefreshing()
}
}
ViewController.swift
class ViewController: UIViewController {
@IBOutlet private weak var tableView: CustomTableView!
private var reloading: Bool = false
private var page: Int = 20
# ・・・省略・・・
override func viewDidLoad() {
super.viewDidLoad()
# ・・・省略・・・
tableView.addTargetToRefreshControl(self, action: #selector(self.refreshArticlesAction), event: .valueChanged)
// refreshControlを呼び出し、ローディングする
tableView.beginRefreshing()
# ・・・省略 (Qiitaからデータ取得する処理) ・・・
tableView.endRefreshing()
tableView.reloadData()
}
@objc private func refreshArticlesAction() {
// 取得数を初期値にする
page = 20
# ・・・省略 (Qiitaからデータ取得する処理) ・・・
tableView.endRefreshing()
tableView.reloadData()
}
}
# ・・・省略・・・
extension ViewController: UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
let height = scrollView.frame.size.height
let contentYoffset = scrollView.contentOffset.y
let distanceFromBottom = scrollView.contentSize.height - contentYoffset
if distanceFromBottom < height {
// 何回も呼ばれてしまうので、リロード中は変数:reloadingをtrueにしておく
if !reloading && page < 100 {
// 取得数を20追加にする
if page <= 100 { page += 20 }
// リロード処理のフラグ変更を「true」
reloading.toggle()
# ・・・省略 (Qiitaからデータ取得する処理) ・・・
// リロード処理のフラグ変更を「false」
reloading.toggle()
tableView.reloadData()
}
}
}
}
}
実装詳細
1. QiitaAPI
の初期取得
-
viewDidLoad
でrefreshControl.beginRefreshing()
を呼び出してローディング開始。 -
Qiita
からデータ取得。 -
refreshControl.endRefreshing()
でローディング停止し、tableView.reloadData()
で内容更新します。
2. 取得しているQiitaAPI
のリフレッシュ
-
UIRefreshControl
のインスタンスにaddTarget
で指定しています。
CustomTableView.swift
func addTargetToRefreshControl(_ target: Any?, action: Selector, event: UIControl.Event) {
self.refreshControl?.addTarget(target, action: action, for: event)
}
ViewController.swift
tableView.addTargetToRefreshControl(self, action: #selector(self.refreshArticlesAction), event: .valueChanged)
- 下に引っ張る度に
@objc private func refreshArticlesAction()
が呼ばれるので、初期取得数 20 に変更し、Qiita
からデータ取得。(省略しておりますが、初期取得数はQiitaAPI
の取得数になります) -
refreshControl.endRefreshing()
でローディング停止し、tableView.reloadData()
で内容更新します。
3. TableView
下部までスクロールした際にQiitaAPI
追加取得
-
ScrollView
のデリゲートメソッドを使い、下までスクロールされたか検出します。 -
distanceFromBottom
何回も呼ばれるのでBool
型の変数reloading
を用意しました。 -
QiitaAPI
の追加取得数は 20 ずつ増やすことにし、100 で上限としました。 -
tableView.reloadData()
で内容更新します。
ViewController.swift
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
let height = scrollView.frame.size.height
let contentYoffset = scrollView.contentOffset.y
let distanceFromBottom = scrollView.contentSize.height - contentYoffset
if distanceFromBottom < height {
// 何回も呼ばれてしまうので、リロード中は変数:reloadingをtrueにしておく
if !reloading && page < 100 {
// 取得数を20追加にする
if page <= 100 { page += 20 }
// リロード処理のフラグ変更を「true」
reloading.toggle()
# ・・・省略 (Qiitaからデータ取得する処理) ・・・
// リロード処理のフラグ変更を「false」
reloading.toggle()
tableView.reloadData()
}
}
}
}