Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Large Navbars #48

Closed
Narsail opened this issue Jan 1, 2018 · 7 comments
Closed

Large Navbars #48

Narsail opened this issue Jan 1, 2018 · 7 comments

Comments

@Narsail
Copy link
Contributor

Narsail commented Jan 1, 2018

Is the SizeProvider called for every data object in the Data Provider when the Collection View Size is changing? I have around 1300 items in my data and when using the Large Navigationbars the scrolling is seriously stuttering.

I checked what the source of the stuttering might be and I found that the sizeProvider of every cell is called every time when the size of the collectionView changes. That might be the culprit.

See the Example:
21zmub

@lkzhao
Copy link
Collaborator

lkzhao commented Jan 2, 2018

CollectionView always invalidate's its layout when its size changes. The reason being that some layouts are calculated from the collectionView's size. I understand that there are situations like this where one of the axis is not used and might change frequently. For UICollectionView, what they do is they ask the layout for shouldInvalidateLayoutForBoundsChange to determine whether or not it should recalculate. We can implement something similar to that. But it would require some more thought since layout in CollectionKit can be composable.
As I can see from your layout, there is actually a better way to optimize. Since you have the same size for every cell, you actually don't need to do layout calculation for each cell. You can implement your own layout that doesn't use the sizeProvider at all.

Try the following layout:

public class FixedSizedLayout<Data>: CollectionLayout<Data> {

  var cellHeight: CGFloat = 84
  var spacing: CGFloat = 10
  var collectionWidth: CGFloat = 0
  var numberOfItems: Int = 0

  public override func layout(collectionSize: CGSize,
                              dataProvider: CollectionDataProvider<Data>,
                              sizeProvider: @escaping (Int, Data, CGSize) -> CGSize) {
    // store the following information necessary when calculating cell frame and contentSize
    numberOfItems = dataProvider.numberOfItems
    collectionWidth = collectionSize.width
  }

  public final override var contentSize: CGSize {
    return CGSize(width: collectionWidth,
                  height: CGFloat(numberOfItems) * (cellHeight + spacing) - spacing)
  }

  public final override func frame(at: Int) -> CGRect {
    return CGRect(x: 0, y: CGFloat(at) * (cellHeight + spacing),
                  width: collectionWidth, height: cellHeight)
  }

  public override func visibleIndexes(activeFrame: CGRect) -> [Int] {
    let minIndex = Int(activeFrame.minY / (cellHeight + spacing))
    let maxIndex = Int(activeFrame.maxY / (cellHeight + spacing))
    return Array(minIndex...maxIndex)
  }
}

Note that layout is very optimized. No matter how many cell you have it will always calculate in O(1) time.

@Narsail
Copy link
Contributor Author

Narsail commented Jan 2, 2018

@lkzhao Your suggestion works really well with one section (as you mentioned) but I actually want to use multiple sections in the CollectionView. While trying I ran into multiple issues when using a CollectionComposer:

  1. When using the CollectionComposer with a FlowLayout and two providers with the FixedSizeLayout I get the following Error: Thread 1: Fatal error: Index out of range in the first line in file CollectionComposer:
func indexPath(_ index: Int) -> (Int, Int) {
    let section = sectionForIndex[index]
    let item = index - sectionBeginIndex[section]
    return (section, item)
} 
  1. When using the Composer without the FlowLayout but the two Providers with the FixedSizeLayout I got this Error: Thread 1: Fatal error: Duplicate values for key: '1.0' in file CollectionView:
private func _loadCells() {
    ...
    let oldIdentifierToCellMap = Dictionary(uniqueKeysWithValues: zip(visibleIdentifiers, visibleCells))
    ...

Any suggestions how to use this tweaked solution with multiple Provider?

@lkzhao
Copy link
Collaborator

lkzhao commented Jan 4, 2018

Hmm weird. Are you using any shared CollectionProvider, CollectionViewProvider, or layout by any chance?

@Narsail
Copy link
Contributor Author

Narsail commented Jan 8, 2018

What do you mean with shared? They are all only used in one CollectionComposer and used by one CollectionView.

Sent with GitHawk

@Narsail
Copy link
Contributor Author

Narsail commented Jan 15, 2018

@lkzhao Do you need a sample project to look for yourself?

@lkzhao
Copy link
Collaborator

lkzhao commented Jan 15, 2018

@Narsail Yes that would be great.

@lkzhao
Copy link
Collaborator

lkzhao commented Jun 23, 2018

Please reopen if you are still experiencing problem.

Also try updating to the latest v2.

@lkzhao lkzhao closed this as completed Jun 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants