利用 UIBackgroundConfiguration 在 collection view cell 顯示圖片
開發 iOS App 時,我們經常使用 collection view 實作格子狀照片牆跟水平滑動的分頁照片牆。從前我們必須自訂 collection view cell 類別,然後加入顯示圖片的 image view。
在 iOS 15 我們有更簡單的方法。 透過 UIBackgroundConfiguration 的 property image & imageContentMode,我們可以設定 cell 顯示的圖片,不用再額外加入 image view 了。
image & imageContentMode 是 iOS 15 新增的 property,因此要 iOS 15 才支援。
接下來我們將示範如何利用 UIBackgroundConfiguration 實現四種常見的 App 畫面。
1. 格子狀照片牆。
2. 水平滑動的全螢幕分頁照片牆。
3. 不分頁的水平滑動照片牆。
4. 顯示網路圖片的格子狀照片牆。
格子狀照片牆
在 assets 加入圖片
設定 cell ID
- 方法1: 從 Interface Builder 加入 cell,設定它的 cell ID。
- 方法2: 呼叫 register 設定 cell ID。
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
到時候 cell 將從程式產生,因此 Interface Builder 的 collection view 不須加入 cell。
設定 cell 大小
假設一排 3 個 cell。
class CollectionViewController: UICollectionViewController {
func configureCellSize() {
let itemSpace: CGFloat = 3
let columnCount: CGFloat = 3
let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout
let width = floor((collectionView.bounds.width - itemSpace * (columnCount-1)) / columnCount)
flowLayout?.itemSize = CGSize(width: width, height: width)
flowLayout?.estimatedItemSize = .zero
flowLayout?.minimumInteritemSpacing = itemSpace
flowLayout?.minimumLineSpacing = itemSpace
}
override func viewDidLoad() {
super.viewDidLoad()
configureCellSize()
}
設定 cell 數量
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 21
}
使用 UIBackgroundConfiguration 設定圖片
UIBackgroundConfiguration 的 image 設定顯示的圖片,imageContentMode 設定圖片縮放的模式,scaleAspectFill 將讓圖片維持比例填滿 cell。
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
backgroundConfiguration.image = UIImage(named: "pic\(indexPath.item)")
backgroundConfiguration.imageContentMode = .scaleAspectFill
cell.backgroundConfiguration = backgroundConfiguration
return cell
}
結果
透過 UIBackgroundConfiguration 我們還可設定許多特別的效果,比方以下例子。
- 設定圓角
設定 cornerRadius。
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
backgroundConfiguration.image = UIImage(named: "pic\(indexPath.item)")
backgroundConfiguration.imageContentMode = .scaleAspectFill
backgroundConfiguration.cornerRadius = 20
- 設定圓角,邊框寬度,邊框顏色,圖片跟 cell 邊界的間距
backgroundInsets 可設定背景的內容跟 cell 上下左右邊界的間距。
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
backgroundConfiguration.image = UIImage(named: "pic\(indexPath.item)")
backgroundConfiguration.imageContentMode = .scaleAspectFill
backgroundConfiguration.cornerRadius = 20
backgroundConfiguration.strokeWidth = 5
backgroundConfiguration.strokeColor = .black
backgroundConfiguration.backgroundInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
水平滑動的分頁照片牆
在 assets 加入圖片跟設定 cell ID
參考格子狀照片牆的說明。
設定 collection view 的捲動方向為水平,勾選 Paging Enabled
Scroll Direction 設為 Horizontal,勾選 Paging Enabled。
設定 cell 大小為螢幕大小
由於 controller 繼承 UICollectionViewController,因此 collectionView.bounds.size 即為螢幕的大小。
class CollectionViewController: UICollectionViewController {
func configureCellSize() {
let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout
flowLayout?.itemSize = collectionView.bounds.size
flowLayout?.estimatedItemSize = .zero
flowLayout?.minimumInteritemSpacing = 0
flowLayout?.minimumLineSpacing = 0
}
override func viewDidLoad() {
super.viewDidLoad()
configureCellSize()
}
設定 cell 數量
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 21
}
使用 UIBackgroundConfiguration 設定圖片
imageContentMode 設為 scaleAspectFit,圖片將維持比例顯示,上下或左右留白。
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
backgroundConfiguration.image = UIImage(named: "pic\(indexPath.item)")
backgroundConfiguration.imageContentMode = .scaleAspectFit
cell.backgroundConfiguration = backgroundConfiguration
return cell
}
結果
不分頁的水平滑動照片牆
我們也可以實現不分頁的水平滑動照片牆,比方以下例子。
設定 cell 的大小為 100 * 100,間距為 10。
使用 UIBackgroundConfiguration 設定圖片。
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
backgroundConfiguration.imageContentMode = .scaleAspectFill
backgroundConfiguration.image = UIImage(named: "pic\(indexPath.item)")
cell.backgroundConfiguration = backgroundConfiguration
return cell
}
顯示網路圖片的格子狀照片牆
搭配 NSCache 暫存網路圖片。
先將 UIBackgroundConfiguration 的 image 設為預設圖片,抓到圖後再將 image 設為抓到的圖片。
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell()
backgroundConfiguration.imageContentMode = .scaleAspectFill
backgroundConfiguration.image = UIImage(systemName: "photo")
cell.backgroundConfiguration = backgroundConfiguration
let feed = feeds[indexPath.item]
NetworkController.shared.fetchImage(url: feed.artworkUrl100) { [weak self] image in
DispatchQueue.main.async {
guard let self = self,
let image = image,
let item = collectionView.indexPath(for: cell)?.item,
feed.id == self.feeds[item].id else { return }
backgroundConfiguration.image = image
cell.backgroundConfiguration = backgroundConfiguration
}
}
return cell
}
網路圖片照片牆的範例連結。