如何在 swift 中使用 IGListKit 创建一个两列集合视图列表

Posted

技术标签:

【中文标题】如何在 swift 中使用 IGListKit 创建一个两列集合视图列表【英文标题】:How to create a two column collection view list with IGListKit in swift 【发布时间】:2018-01-04 12:40:21 【问题描述】:

我正在使用 IGListKit 库 (IGListKit)。 我想创建一个两列集合视图列表,如下所示。 我已经阅读了 IGListKit 手册,但我不明白如何实现。

我在sizeForItem 中传递了正确的宽度,但列变成了 1。

你能给我什么建议吗?

其他信息

以下是我的代码及其输出截图。

第一个代码是 ViewController。

class ViewController: UIViewController 
    lazy var adapter: ListAdapter = 
        return ListAdapter(updater: ListAdapterUpdater(), viewController: self)
    ()

    @IBOutlet weak var collectionView: UICollectionView!

    let channels = [
        Channel(id: "1", color: UIColor.black),
        Channel(id: "2", color: UIColor.blue),
        Channel(id: "3", color: UIColor.red),
        Channel(id: "4", color: UIColor.yellow),
        Channel(id: "5", color: UIColor.green),
        ]

    override func viewDidLoad() 
        super.viewDidLoad()

        self.adapter.collectionView = self.collectionView
        self.adapter.dataSource = self
    

    func objects(for listAdapter: ListAdapter) -> [ListDiffable] 
        return self.channels as! [ListDiffable]
    

    func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController 
        return ChannelSectionController()
    

    func emptyView(for listAdapter: ListAdapter) -> UIView? 
        return nil
    

下面是SectionController。

final class ChannelSectionController: ListSectionController 

    var channel: Channel?

    override func numberOfItems() -> Int 
        return 1
    

    override func sizeForItem(at index: Int) -> CGSize 
        let length = collectionContext!.containerSize.width / 4
        return CGSize(width: length, height: length)
    

    override func cellForItem(at index: Int) -> UICollectionViewCell 
        guard let channel = channel else 
            fatalError("channel is nil.")
        

        guard let cell = self.collectionContext?.dequeueReusableCellFromStoryboard(withIdentifier: "ChannelCell", for: self, at: index) as? ChannelCollectionViewCell else 
            fatalError()
        
        cell.channel = channel // Update the cell label and color.
        return cell
    

    override func didUpdate(to object: Any) 
        self.channel = object as? Channel
    

    override func didSelectItem(at index: Int) 

如您所见,sizeForItem() 返回的宽度比帧宽度小。 但是,输出列变成了一行。

【问题讨论】:

你如何计算 CollectionView 项目的大小? 你在继承IGListSectionController吗?单元格的大小应该在里面处理。另外,你符合适配器数据源(adapter.dataSource = self)吗? 请发布您的代码 感谢您的 cmets。 @nuridinselimko 我只是用我的原始代码和屏幕截图发布了附加信息。如果能帮到你就太好了。 【参考方案1】:

基于this 文章(底部)如何创建对象,您应该像这样创建对象:

class ChannelCollection: ListDiffable 

var id : String
var channels: [Channel]
init(id: String,channels: [Channel]) 
    self.id = id
    self.channels = channels

func isEqual(toDiffableObject object: ListDiffable?) -> Bool 
    return true //compare your object here, I returned true for test

func diffIdentifier() -> NSObjectProtocol 
    return id as NSObjectProtocol


你的视图控制器应该是这样的:

class ViewController: UIViewController,ListAdapterDataSource 
lazy var adapter: ListAdapter = 
    return ListAdapter(updater: ListAdapterUpdater(), viewController: self)
()
var items : [Any] = []
@IBOutlet weak var collectionView: UICollectionView!
var channelCollection : ChannelCollection?
let channels = [
    Channel(id: "1", color: UIColor.black),
    Channel(id: "2", color: UIColor.blue),
    Channel(id: "3", color: UIColor.red),
    Channel(id: "4", color: UIColor.yellow),
    Channel(id: "5", color: UIColor.green),
    ]

override func viewDidLayoutSubviews() 
    super.viewDidLayoutSubviews()
    collectionView.frame = view.bounds


override func viewDidLoad() 
    super.viewDidLoad()
    self.channelCollection = ChannelCollection.init(id: "1", channels: self.channels)
    self.items.append(self.channelCollection as Any)
    self.adapter.collectionView = self.collectionView
    self.adapter.dataSource = self


func objects(for listAdapter: ListAdapter) -> [ListDiffable] 
    return self.items as! [ListDiffable]


func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController 
    return ChannelSectionController.init(channelCollection: self.channelCollection!)


func emptyView(for listAdapter: ListAdapter) -> UIView? 
    return nil

你的 ListSectionController:

final class ChannelSectionController: ListSectionController 

var channel: Channel?

var channelCollection : ChannelCollection?
init(channelCollection: ChannelCollection)

    self.channelCollection = channelCollection

override func numberOfItems() -> Int 
    return (self.channelCollection?.channels.count)!


override func sizeForItem(at index: Int) -> CGSize 
    let length = collectionContext!.containerSize.width / 4
    return CGSize(width: length, height: length)


override func cellForItem(at index: Int) -> UICollectionViewCell 


    guard let cell = self.collectionContext?.dequeueReusableCellFromStoryboard(withIdentifier: "ChannelCell", for: self, at: index) as? ChannelCollectionViewCell else 
        fatalError()
    
    //cell.channel = channel // Update the cell label and color.
    return cell


override func didUpdate(to object: Any) 
    self.channel = object as? Channel


override func didSelectItem(at index: Int) 

所以我在这里改变的是你添加了5个部分,更好的做法是添加一个部分和5行,这段代码输出你想要的东西,试试吧。

【讨论】:

我在这里添加了我的代码。你能给我什么建议吗?【参考方案2】:

单细胞/单节

对于那些想要在每个部分使用单个单元格的人,这与在单个 sectionSectionController 中使用多个单元格/行的公认答案不同,您只需使用 IGListKit 的专用布局,如下所示:-

let layout = ListCollectionViewLayout(stickyHeaders: false, topContentInset: 0, stretchToEdge: true)

这将与普通 collectionViewLayout 的行为方式相同,方法是确保在创建新行之前部分填充宽度。

【讨论】:

【参考方案3】:

只需在部分控制器中设置每个项目的大小即可。

通过在您的部分控制器中覆盖 sizeForItem(at index: Int) 来做到这一点。

例如: 假设每个单元格之间有 16 像素的空间,并且想要使用 2 列布局:

override func sizeForItem(at index: Int) -> CGSize 
  guard let contextOfCollection = collectionContext, 
    let entry = entry 
    else  
      return .zero
  

  let objectWidth = (contextOfCollection.containerSize.width - 16 - 16)/2 // dividing by 2 because
                                                                          // you want 2 columns
  return CGSize(width: objectWidth, height:objectWidth)

或者您可以设置固定的单元格大小并使用 insets/autolayout/constraints 很好地填充单元格。

【讨论】:

以上是关于如何在 swift 中使用 IGListKit 创建一个两列集合视图列表的主要内容,如果未能解决你的问题,请参考以下文章

[iOS开发]IGListKit框架初学

如何使用 IGListKit 强制重新加载所有部分?

如何让 IGListKit 在水平滚动的 UICollectionView 中分隔项目?

如何使用 IGListKit 滚动到部分的底部

IGListKit:获取当前可见的单元格索引

使用嵌套适配器垂直滚动时出现滞后问题 | IGListKit