#30 利用 Compositional Layout 製作特殊版型照片牆(Flickr API)
UICollectionViewCompositionalLayout / Flickr API / Preview Tool
加入 collectionView / 抓資料放屬性 photos
用到 UICollectionView 的 init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout)
生成 collectionView。
createLayout 函式後面談。
遵從 UICollectionViewDataSource
設定 … numberOfItemsInSection …,設定 … cellForItemAt …,把資料內的 imageUrl 傳給 cell 的 imageURL,再拿 cell 的 imageURL 下載圖片,最後把 image 物件放進 cell.imageView.image 顯示。
MyCollectionViewCell
import UIKitclass MyCollectionViewCell: UICollectionViewCell {
static let identifier = "MyCollectionViewCell"
var imageURL: URL!
let imageView: UIImageView = {
let imageView = UIImageView()
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(imageView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = contentView.bounds
}
}
先前呼叫的 createLayout() 最終回傳 UICollectionViewCompositionalLayout 的
init(section: NSCollectionLayoutSection)
生成的 UICollectionViewLayout 型別物件
重點說明:以右上角 doubletVerticalGroup 和 doubletItem 為例。
let doubletItem = NSCollectionLayoutItem(
// NSCollectionLayoutSize 決定該物件與「所屬容器」的比例關係
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(1) //所屬group已經有count:2,故填什麼都沒差
)
)let doubletVerticalGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1/3),
heightDimension: .fractionalHeight(1)
),
subitem: doubletItem, count: 2 //該group的subitem是誰及其數量
)//設定contentInsets,往物件內「裁切邊距」doubletVerticalGroup.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: padding/2, bottom: 0, trailing: padding/2)//設定interItemSpacing,在item間「推出邊距」(不會裁切)
doubletVerticalGroup.interItemSpacing = NSCollectionLayoutSpacing.fixed(padding)
即時預覽功能 Snippets:
#if canImport(SwiftUI) && DEBUG
import SwiftUI@available(iOS 13.0, *)
struct UIViewControllerPreview<ViewController: UIViewController>: UIViewControllerRepresentable {
let viewController: ViewControllerinit(_ builder: @escaping () -> ViewController) {
viewController = builder()
}func makeUIViewController(context: Context) -> some UIViewController {
viewController
}func updateUIViewController(_ uiViewController: UIViewControllerType, context: UIViewControllerRepresentableContext<UIViewControllerPreview<ViewController>>) {
return
}
}
#endif#if canImport(SwiftUI) && DEBUG
import SwiftUI// 可加入多個裝置
let deviceNames: [String] = [
"iPhone 13 Pro Max"
]@available(iOS 13.0, *)
struct ViewController_Previews: PreviewProvider {
static var previews: some View {
ForEach(deviceNames, id: \.self) { deviceName in
UIViewControllerPreview {
ViewController()
}
.previewDevice(PreviewDevice(rawValue: deviceName))
.previewDisplayName(deviceName)
}.previewInterfaceOrientation(.portrait)
}
}
#endif
參考資料
・UICollectionViewCompositionalLayout 原理:
・UICollectionViewCompositionalLayout 範例:
・Flickr API
・讓 View Controller & UIKit View 也能享用 SwiftUI 方便的 preview