如何在 swift 中使用 @resultbuilder 使用 UICollectionView?

Posted

技术标签:

【中文标题】如何在 swift 中使用 @resultbuilder 使用 UICollectionView?【英文标题】:How can i use UICollectionView using @resultbuilder in swift? 【发布时间】:2021-11-05 14:05:47 【问题描述】:

我想使用 @resultbuilder 在 UIKit 中创建我自己的声明性 UICollectionView,类似于我们在 SwiftUI 中使用 List 获得的内容。

我的@resultBuilder 创建快照如下所示:

@resultBuilder
struct SnapshotBuilder 
    
    static func buildBlock(_ components: ListItemGroup...) -> [ListItem] 
        return components.flatMap  $0.items 
    
    
    static func buildFinalResult(_ component: [ListItem]) -> NSDiffableDataSourceSectionSnapshot<ListItem> 
        var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<ListItem>()
        sectionSnapshot.append(component)
        return sectionSnapshot
    

我还需要使用以下扩展将ListItemGroup 传递给SnapshotBuilder 并得到[ListItem]

struct ListItem: Hashable 
    
    let title: String
    let image: UIImage?
    var children: [ListItem]
    
    init(_ title: String, children: [ListItem] = []) 
        self.title = title
        self.image = UIImage(systemName: title)
        self.children = children
    


protocol ListItemGroup 
    var items: [ListItem]  get 


extension Array: ListItemGroup where Element == ListItem 
    var items: [ListItem]  self 


extension ListItem: ListItemGroup 
    var items: [ListItem]  [self] 

我的List 类如下所示:

final class List: UICollectionView 
    
    private enum Section 
        case main
    
    
    private var data: UICollectionViewDiffableDataSource<Section, ListItem>!
    
    init(@SnapshotBuilder snapshot: () -> NSDiffableDataSourceSectionSnapshot<ListItem>) 
        super.init(frame: .zero, collectionViewLayout: List.createLayout())
        
        configureDataSource()
        data.apply(snapshot(), to: .main)
    
    
    required init(coder: NSCoder) 
        super.init(coder: coder)!
    
    
    private static func createLayout() -> UICollectionViewLayout 
        let layoutConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
        return UICollectionViewCompositionalLayout.list(using: layoutConfig)
    
    
    private func configureDataSource() 
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, ListItem> 
            (cell, indexPath, item) in
            
            var content = cell.defaultContentConfiguration()
            content.image = item.image
            content.text = item.title
        
        
        data = UICollectionViewDiffableDataSource<Section, ListItem>(collectionView: self) 
            (collectionView: UICollectionView, indexPath: IndexPath, identifier: ListItem) -> UICollectionViewCell? in
            
            let cell = collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
            cell.accessories = [.disclosureIndicator()]
            return cell
        
    

我正在像这样使用List

class DeclarativeViewController: UIViewController 
    
    override func viewDidLoad() 
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        
        let collectionView = List 
            ListItem("Cell 1")
            ListItem("Cell 2")
            ListItem("Cell 3")
            ListItem("paperplane.fill")
            ListItem("doc.text")
            ListItem("book.fill")
        
        collectionView.frame = view.bounds
        collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(collectionView)
       

它似乎工作。我根据数据计数获取单元格行,但单元格是空的,如下所示:

我需要进行哪些更改才能使其正常工作?我的错误在哪里?我可以在UICollectionView 中定义一个数据源吗?谢谢你的回答。

【问题讨论】:

【参考方案1】:

您忘记应用配置。

var content = cell.defaultContentConfiguration()
content.image = item.image
content.text = item.title
cell.contentConfiguration = content // this is important

由于UIListContentConfigurationstruct,所以当您执行var content = cell.defaultContentConfiguration() 时,您只会得到它的副本。

【讨论】:

谢谢 Rico,我的错 :)

以上是关于如何在 swift 中使用 @resultbuilder 使用 UICollectionView?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 kotlin native 中使用 swift 库?

如何在 Swift 中使用 Apple 地图 - 你必须使用 C 还是 Swift 可以?

如何在 Swift 中使用 MKPolylineView

如何在 Swift 中使用`syslog`

如何在 swift 项目中使用 TPKeyboardAvoiding?

如何在 Playground 中使用 Swift 包管理器