Instagram / Instagram/IGListKit

Section Controllers with multiple cells, horizontally laid out

Open
#1,210 3 comments 0 reactions 0 assignees View on GitHub
question
Dominant language
Objective-C
Stars
13.1k
Forks
1.5k
PR merge metrics
No merged PRs in 30d

Description

## New issue checklist

- [x] I have reviewed the [`README`](https://github.com/Instagram/IGListKit/blob/master/README.md) and [documentation](http://instagram.github.io/IGListKit)
- [x] I have searched [existing issues](https://github.com/Instagram/IGListKit/issues) and this is not a duplicate

### General information

- `IGListKit` version:
- iOS version(s): 11.3
- CocoaPods/Carthage version:
- Xcode version: 9.3
- Devices/Simulators affected: N/A
- Reproducible in the demo project? (Yes/No): N/A
- Related issues: not found

Hi IG team,

First of all, thank you for sharing this framework, I've been using it extensively for a few months and it has simplified my life drastically. So far I've always been able to implement the UX I wanted by doing research and looking at the examples you provided, but I finally hit a wall this week.

As illustrated on the drawing below, I need to create a nested section that scrolls horizontally and hosts a bunch of section controllers, each containing 2 cells. What I am not managing to do is have the 2 cells be laid out next to each other horizontally instead of stacked on top of each other, in each (blue) section controller.

I am using IGListkit's ListCollectionViewLayout for the nested collection view, which allows me to have the blue section controllers nicely laid out horizontally as shown on the drawing, but cannot get the 2 cells not to be stacked on top of each other.

I am attaching a simplified version of the code, any guidance on how to this would be most appreciated.

Thanks again!

![iglistkit issue illustration](https://user-images.githubusercontent.com/24532043/42404179-f2a8f9d2-813b-11e8-991e-9498ef857502.png)

**Simplified code for the blue section controller**
```
class BlueSectionController : ListSectionControllerBase{

//Space between pods
static let customInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
static let sectionHeight : CGFloat = OrangeCell.cellHeight + BlueSectionController.customInsets.top + BlueSectionController.customInsets.bottom

var viewModel : ViewModel?

override init() {
super.init()
inset = BlueSectionController.customInsets
}

override func numberOfItems() -> Int {
return 2
}

override func sizeForItem(at index: Int) -> CGSize {
guard let context = collectionContext else {return .zero}

switch index{
case 0: //Orange cell (cell 1)
return CGSize(width: OrangeCell.cellWidth, height: OrangeCell.cellHeight)
default: //Green cell (cell 2)
let width = context.containerSize.width - OrangeCell.cellWidth - 50 //50 = space on the right to allow next section to tip in
return CGSize(width: width, height: GreenCell.cellHeight) //Both cells have the same height
}
}

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

guard let context = collectionContext else {return UICollectionViewCell()}

switch index{
case 0: //Orange cell (cell 1)
guard let cell = context.dequeueReusableCell(withNibName: "OrangeCell", bundle: nil, for: self, at: index) as? OrangeCell else {return UICollectionViewCell()}
//Configure cell...
return cell

default: //Green cell (cell 2)
guard let cell = context.dequeueReusableCell(withNibName: "GreenCell", bundle: nil, for: self, at: index) as? GreenCell else {return UICollectionViewCell()}
//Configure cell...
return cell
}
}

//This function is used to hand an object to the section controller. Note this method will always be called before any of the cell protocol methods.
override func didUpdate(to object: Any) {
guard let viewModel = object as? ViewModel else {return}
self.viewModel = viewModel
}
}

```

**Simplified code for the nested section controller**
```
class NestedSectionController: ListSectionController{

final lazy var listAdapter: ListAdapter = { [unowned self] _ in
let adapterUpdater = ListAdapterUpdater()
//adapterUpdater.delegate = self
let adapter = ListAdapter(updater: adapterUpdater, viewController: self.viewController)
return adapter
}()

//Space between this section and the next
static let customInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
var viewModelArray : [ViewModel]?
var

override init() {
super.init()
listAdapter.dataSource = self
}

override func numberOfItems() -> Int {
return 1
}

override func didUpdate(to object: Any) {
guard let nestedSectionToken = object as? NestedSectionToken else { return }
self.viewModelArray = nestedSectionToken.viewModelArray
}

override func didSelectItem(at index: Int) {
}


override func sizeForItem(at index: Int) -> CGSize {
guard let context = collectionContext else {return .zero}
return CGSize(width: context.containerSize.width, height: BlueSectionController.sectionHeight * 2)
}

override func cellForItem(at index: Int) -> UICollectionViewCell {
guard let cell = collectionContext?.dequeueReusableCell(of: HorizontalEmbeddedCollectionViewCell.self, for: self, at: index) as? HorizontalEmbeddedCollectionViewCell else {return UICollectionViewCell()}
listAdapter.collectionView = cell.collectionView
listAdapter.scrollViewDelegate = self
listAdapter.collectionView?.reloadData() //Needed to avoid crash (see https://github.com/Instagram/IGListKit/issues/952)
return cell
}
}

extension NestedSectionController: ListAdapterDataSource {

func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return arrayOfViewModels as [ListDiffable]
}

func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
guard let viewModel = object as? ViewModel else {return ErrorSectionController()}

let section = BlueSectionController()
//Configure section...
return section
}

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

}
```

**Code for the Embedded CollectionView cell**
```
final class HorizontalEmbeddedCollectionViewCell: UICollectionViewCell {

static let cellHeight : CGFloat = MyPodCellSectionController.sectionHeight

lazy var collectionView: UICollectionView = {
let layout = ListCollectionViewLayout(stickyHeaders: false, scrollDirection: .horizontal, topContentInset: 0, stretchToEdge: false)
let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
view.showsHorizontalScrollIndicator = false
view.showsVerticalScrollIndicator = false
view.backgroundColor = .white
view.alwaysBounceVertical = false
view.alwaysBounceHorizontal = true
self.contentView.addSubview(view)
return view
}()

override func layoutSubviews() {
super.layoutSubviews()
collectionView.frame = contentView.bounds
}

}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.