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

Support for more than one item in the cross-axis #38

Open
gcox opened this issue Mar 4, 2019 · 7 comments
Open

Support for more than one item in the cross-axis #38

gcox opened this issue Mar 4, 2019 · 7 comments
Labels
help wanted Extra attention is needed

Comments

@gcox
Copy link

gcox commented Mar 4, 2019

Currently, this lib forces the cross axis size of a cell to match that of the collection view. The App Store has another type of horizontally peeking collection view where multiple cells are displayed vertically in each page. The lib could allow specifying the number of cross-axis items to show, then use that value to calculate the appropriate item size in the collectionView:layout:sizeForItemAt: delegate func.

Screenshot of the UI I'm referring to
img_0906

@MaherKSantina
Copy link
Owner

Thanks @gcox for raising this issue! That's a good idea to implement. However, it's a bit challenging implement as we need to take into account inter-item/cell spacing and size for items. Also, calculation of current index and scrolling to items at specific indices will change.
I'd consider this as nice to have since you can do a similar functionality by implementing a collection view cell that has a UITableView/UIStackView which shows x items at a time.
If you have any ideas of how to make it simpler to implement this functionality it'd be of great help.
Please let me know what you think

@gcox
Copy link
Author

gcox commented Mar 4, 2019

@MaherKSantina Here's the basic implementation details. It is not thoroughly tested and I'm sure I'm missing some edge cases, just want to see if you had any other thoughts on this. I can submit a PR later this week if you don't see any glaring issues here.

fileprivate lazy var itemCrossLength: (UIView) -> CGFloat = {
  var length: CGFloat = self.scrollDirection.crossLength(for: $0)
  let allItemsLength = (length
    - (CGFloat(self.numberOfItemsToShowInCrossAxis + 1) * (self.cellSpacing))
    - 2)
  let finalLength = allItemsLength / CGFloat(self.numberOfItemsToShowInCrossAxis)
  return max(0, finalLength)
}

open func scrollView(_ scrollView: UIScrollView, indexForItemAtContentOffset contentOffset: CGPoint) -> Int {
  let mainAxisItemLength = itemLength(scrollView) + cellSpacing
  guard mainAxisItemLength > 0 else {
    return 0
  }
  let mainAxisOffset = self.scrollDirection.value(for: contentOffset)
  guard numberOfItemsToShowInCrossAxis > 1 else {
    return Int(round(mainAxisOffset / mainAxisItemLength))
  }
  let crossAxisItemLength = itemCrossLength(scrollView) + cellSpacing
  let crossAxisOffset = self.scrollDirection.crossValue(for: contentOffset)
  let minimumIndex = Int(round(mainAxisOffset / mainAxisItemLength)) * numberOfItemsToShowInCrossAxis
  let index = minimumIndex + Int(round(crossAxisOffset/crossAxisItemLength))
  return index
}

open func scrollView(_ scrollView: UIScrollView, contentOffsetForItemAtIndex index: Int) -> CGFloat {
  return CGFloat(index / numberOfItemsToShowInCrossAxis) * (itemLength(scrollView) + cellSpacing)
}

// Assumes we want the full height taken up by equally sized items
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  var defaultSize = collectionView.frame.size
  if numberOfItemsToShowInCrossAxis > 1 {
    let crossAxisItems = CGFloat(numberOfItemsToShowInCrossAxis)
    let crossAxisGapTotal = (crossAxisItems - 1) * cellSpacing

    switch scrollDirection {
    case .horizontal:
      defaultSize.height = (defaultSize.height - crossAxisGapTotal) / crossAxisItems
    case .vertical:
      defaultSize.width = (defaultSize.width - crossAxisGapTotal) / crossAxisItems
    }
  }
  return scrollDirection.size(for: itemLength(collectionView), defaultSize: defaultSize)
}

public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
  ...

  // Only line that needs to change in this function
  let numberOfItemsToScroll = getNumberOfItemsToScroll(scrollDistance: currentScrollDistance, scrollWidth: itemLength(scrollView)) *
    numberOfItemsToShowInCrossAxis
  
  ...
}

That code depends on a couple of new extension methods on UICollectionViewScrollDirection just to return the 'crossLength', 'crossValue' numbers. Left them out since they're so simple.

@MaherKSantina
Copy link
Owner

Ohh @gcox thank you for the code snippet! I'll definitely take a look at it in the weekend

@Sk8er22
Copy link

Sk8er22 commented Jan 10, 2020

this is actually supported?

@MaherKSantina
Copy link
Owner

@Sk8er22 sadly it's not implemented yet. I was focusing on other features that I thought were more important. I deprioritized this one because you can achieve the same behavior by creating a collection view cell that has 3 items. I'm thinking about the complexity this feature adds to the library and it feels like there are a lot of things to take into consideration so I'm still hesitant about it.

Do you think you can achieve the same behavior by creating a collection view cell with a vertical stack view and add the views in it?

@Sk8er22
Copy link

Sk8er22 commented Jan 10, 2020

I did it doing a custom big cell that contains all the possible stacks. Thanks anyway!

@MaherKSantina
Copy link
Owner

@Sk8er22 sounds great! I'll add a help-wanted tag in the meantime

Have a great day!

@MaherKSantina MaherKSantina added the help wanted Extra attention is needed label Jan 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants