Как создать список представлений коллекции из двух столбцов с IGListKit в 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() достаточно мал, чем ширина кадра. Однако выходной столбец становится одной строкой.

1 ответ

Решение

Основываясь на этой статье (внизу), как создать объект, вы должны создать свой объект следующим образом:

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 строк, этот код выводит то, что вы хотите, просто попробуйте.

Одна ячейка / одна секция

Для тех, кто хочет использовать одну ячейку для каждого раздела, в отличие от принятого ответа, который использует несколько ячеек / строк в одном sectionSectionController, вам просто нужно использовать выделенный макет из IGListKit, например:-

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

Это будет вести себя так же, как и обычный collectionViewLayout, если перед созданием новой строки убедитесь, что секции заполняют всю ширину.

Просто установите размер для каждого элемента в контроллере раздела.

Сделайте это, переопределив 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)
}

Или вы можете установить фиксированный размер ячейки и использовать вставки / автоматическое размещение / ограничения для удобного заполнения ячеек.

Другие вопросы по тегам