APIから画像URLを取得して画像をダウンロードし、UICollectionViewに表示するサンプルを実装してみました。
※2019/11 追記
以下記事でページネーションを実装しました。
■開発環境
・Xcode 10.3
・Swift 5.0.1
■サンプルのイメージ
■実装手順
1.Nukeをインストール
pod 'Nuke'
2.Main.storyboardでUICollectionViewを配置し、上下左右の制約を0にする
※Collection View Cellは削除
3.Collection View Flow Layoutを画像の通りに設定
4.画面左上のFile>New>File>Cocoa Touch ClassでUICollectionViewCellを追加
※Also create XIB fileにチェックを入れる
5.CollectionViewCell.xibにUIImageViewとUILabelを配置
※UIImageViewの制約は上下左右0、UILabelの制約は左と下が0、高さ15、幅30以上
※その他設定
・UIImageViewのContent ModeをAspect Fillに変更
・UILabelのFontをSystem 11.0に変更
・UILabelの背景の色は以下画像の通り設定
6.5で配置したUIImageViewとUILabelをCollectionViewCell.swiftに関連づける
CollectionViewCell.swift
import UIKit class CollectionViewCell: UICollectionViewCell { @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var label: UILabel! override func awakeFromNib() { super.awakeFromNib() } }
7. ViewController.swiftに以下実装
ViewController.swift
import UIKit import Nuke struct Item: Codable { var hits: [Hits] struct Hits: Codable { var user: String var previewURL: String var webformatURL: String } } class ViewController: UIViewController { @IBOutlet weak var collectionView: UICollectionView! private var items: Item? private let preheater = ImagePreheater() override func viewDidLoad() { super.viewDidLoad() self.collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CollectionViewCell") self.collectionView.delegate = self self.collectionView.dataSource = self self.collectionView.prefetchDataSource = self self.setUpPixabayItems() let refreshControl = UIRefreshControl() self.collectionView.refreshControl = refreshControl refreshControl.addTarget(self, action: #selector(ViewController.refresh(sender:)), for: .valueChanged) } @objc func refresh(sender: UIRefreshControl) { self.setUpPixabayItems() sender.endRefreshing() } private func setUpPixabayItems() { self.getPixabayItems(completion: { (item) in self.items = item DispatchQueue.main.async { self.collectionView.reloadData() } }) } private func getPixabayItems(completion: @escaping (Item) -> ()) { if let url = URL(string: "https://pixabay.com/api/?key={KEY}&image_type=photo") { 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: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { if let url = URL(string: self.items?.hits[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 - 2 return CGSize(width: cellWidth, height: cellWidth) } } extension ViewController: UICollectionViewDataSource { // セルの数 func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.items?.hits.count ?? 0 } // セルの設定 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell cell.imageView.image = nil cell.label.text = nil let item = self.items?.hits[indexPath.row] cell.label.text = item?.user let previewUrl = URL(string: item?.previewURL ?? "")! Nuke.loadImage(with: previewUrl, into: cell.imageView) return cell } } extension ViewController: UICollectionViewDataSourcePrefetching { func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { let urls = indexPaths.map { URL(string: self.items?.hits[$0.row].previewURL ?? "") } preheater.startPreheating(with: urls as! [URL]) } func collectionView(_ collectionView: UICollectionView, cancelPrefetchingForItemsAt indexPaths: [IndexPath]) { let urls = indexPaths.map { URL(string: self.items?.hits[$0.row].previewURL ?? "") } preheater.stopPreheating(with: urls as! [URL]) } }
■参考リンク
・https://developer.apple.com/documentation/uikit/uicollectionview