swift 如何使用 IGListKit 创建两列集合视图列表
How to create a two column collection view list with IGListKit in swift
我正在使用 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()
返回的宽度比框架宽度足够小。
但是,输出列变成了一行。
根据 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
}
}
你的 viewcontroller 应该是这样的:
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行,这段代码输出你想要的东西,试试吧。
只需在您的部分控制器中设置每个项目的大小。
通过覆盖您的部分控制器中的 sizeForItem(at index: Int)
来完成此操作。
例如:
假设每个单元格之间有 16 个 space 像素,并且想要使用 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 来很好地填充单元格。
单cell/Single节
对于那些想要在每个部分使用单个单元格的人,这与在单个 sectionSectionController 中使用多个 cells/rows 的已接受答案不同,您只需使用 IGListKit 中的专用布局,如下所示:-
let layout = ListCollectionViewLayout(stickyHeaders: false, topContentInset: 0, stretchToEdge: true)
这与普通 collectionViewLayout 的行为方式相同,确保各部分在创建新行之前填满宽度。
我正在使用 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()
返回的宽度比框架宽度足够小。
但是,输出列变成了一行。
根据 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
}
}
你的 viewcontroller 应该是这样的:
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行,这段代码输出你想要的东西,试试吧。
只需在您的部分控制器中设置每个项目的大小。
通过覆盖您的部分控制器中的 sizeForItem(at index: Int)
来完成此操作。
例如: 假设每个单元格之间有 16 个 space 像素,并且想要使用 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 来很好地填充单元格。
单cell/Single节
对于那些想要在每个部分使用单个单元格的人,这与在单个 sectionSectionController 中使用多个 cells/rows 的已接受答案不同,您只需使用 IGListKit 中的专用布局,如下所示:-
let layout = ListCollectionViewLayout(stickyHeaders: false, topContentInset: 0, stretchToEdge: true)
这与普通 collectionViewLayout 的行为方式相同,确保各部分在创建新行之前填满宽度。