【Swift】UICollectionView/APIから画像URLを取得して画像を表示(https://www.hfoasi8fje3.work/entry/2019/08/22/224038)でAPIから画像取得後UICollectionViewに表示する実装についてまとめました。
今回は上記記事の続きとして、ページネーションを実装してみました。
※今回もPixabay APIを使用しています。
■開発環境
・Xcode 10.3
・Swift 5.0.1
■コード
import UIKit import Nuke struct Item: Codable { var hits: [Hits] struct Hits: Codable { var previewURL: String var tags: String var user: String var webformatURL: String } } class ViewController: UIViewController { @IBOutlet weak var pixabayCollectionView: UICollectionView! private var items: [Item.Hits] = [] private let preheater = ImagePreheater() private var pageNo = 1 private var isLoadingList = false override func viewDidLoad() { super.viewDidLoad() self.pixabayCollectionView.register(UINib(nibName: "pixabayCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "pixabayCollectionViewCell") self.pixabayCollectionView.delegate = self self.pixabayCollectionView.dataSource = self self.pixabayCollectionView.prefetchDataSource = self self.setUpPixabayItems() let refreshControl = UIRefreshControl() self.pixabayCollectionView.refreshControl = refreshControl refreshControl.addTarget(self, action: #selector(ViewController.refresh(sender:)), for: .valueChanged) } @objc func refresh(sender: UIRefreshControl) { // ページ番号を元に戻す self.pageNo = 1 self.items = [] self.setUpPixabayItems() sender.endRefreshing() } private func setUpPixabayItems() { self.getPixabayItems(pageNo: self.pageNo, completion: { (item) in self.pageNo += 1 self.items.append(contentsOf: item.hits) DispatchQueue.main.async { self.isLoadingList = false self.pixabayCollectionView.reloadData() } }) } private func getPixabayItems(pageNo: Int, completion: @escaping (Item) -> ()) { let url = URL(string: "https://pixabay.com/api/")! var components = URLComponents(url: url, resolvingAgainstBaseURL: false) components?.queryItems = [URLQueryItem(name: "key", value: "{APIKey}")] + [URLQueryItem(name: "page", value: "\(pageNo)")] + [URLQueryItem(name: "per_page", value: "100")] + [URLQueryItem(name: "q", value: "sea")] + [URLQueryItem(name: "image_type", value: "photo")] let queryStringAddedUrl = components?.url if let url = queryStringAddedUrl { let task = URLSession.shared.dataTask(with: url) { data, response, error in if let data = data { do { let decoder = JSONDecoder() let items = try decoder.decode(Item.self, from: data) completion(items) } catch { print("Serialize Error") } } else { print(error ?? "Error") } } task.resume() } } } extension ViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { // isLoadingListがfalseの時だけsetUpPixabayItemsを実行する if (((scrollView.contentOffset.y + scrollView.frame.size.height) > scrollView.contentSize.height) && !self.isLoadingList) { // setUpPixabayItemsを実行している間に追加でsetUpPixabayItemsを実行しないようにisLoadingListをtrueに変更 self.isLoadingList = true self.setUpPixabayItems() } } } // セル選択時の処理 extension ViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if let url = URL(string: self.items[indexPath.row].webformatURL) { UIApplication.shared.open(url) } } } // セルの大きさ extension ViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let numberOfCell: CGFloat = 3 let cellWidth = UIScreen.main.bounds.size.width / numberOfCell - 6 return CGSize(width: cellWidth, height: 160) } } extension ViewController: UICollectionViewDataSource { // セルの数 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.items.count } // セルの設定 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "pixabayCollectionViewCell", for: indexPath) as! pixabayCollectionViewCell let item = self.items[indexPath.row] let previewUrl = URL(string: item.previewURL)! Nuke.loadImage(with: previewUrl, into: cell.pixabayImageView) cell.imageTagLabel.text = item.tags cell.imageCreatorNameLabel.text = item.user return cell } } extension ViewController: UICollectionViewDataSourcePrefetching { func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { let urls = indexPaths.map { URL(string: self.items[$0.row].previewURL) } self.preheater.startPreheating(with: urls as! [URL]) } func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) { let urls = indexPaths.map { URL(string: self.items[$0.row].previewURL) } self.preheater.stopPreheating(with: urls as! [URL]) } }
■参考リンク
・https://pixabay.com/api/docs/
・https://stackoverflow.com/questions/35367496/swift-tableview-pagination