Open gcox opened 5 years ago
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
@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.
Ohh @gcox thank you for the code snippet! I'll definitely take a look at it in the weekend
this is actually supported?
@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?
I did it doing a custom big cell that contains all the possible stacks. Thanks anyway!
@Sk8er22 sounds great! I'll add a help-wanted tag in the meantime
Have a great day!
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](https://user-images.githubusercontent.com/251512/53732681-b5338580-3e4c-11e9-9854-70ab555b89c2.jpeg)