LoginSignup
1

More than 1 year has passed since last update.

TableViewでのデータの読込・リフレッシュ・更新についての処理

Last updated at Posted at 2020-11-15

はじめに

Qiitaが提供しているAPIを使用して、TableViewに記事を表示する際に、データの読込リフレッシュ更新について実装しましたので備忘録として投稿します。

概要

  1. QiitaAPIの初期取得
  2. 取得しているQiitaAPIのリフレッシュ
  3. 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の初期取得

output1.gif

  • viewDidLoadrefreshControl.beginRefreshing()を呼び出してローディング開始。
  • Qiitaからデータ取得。
  • refreshControl.endRefreshing()でローディング停止し、tableView.reloadData()で内容更新します。

2. 取得しているQiitaAPIのリフレッシュ

output3.gif

  • 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追加取得

output2.gif

  • 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()
            }
        }
    }
}

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1