以编程方式滚动到UICollectionView内的补充视图

我正在使用UICollectionView以分段显示照片。 每个部分都有一个补充视图作为标题,并通过方法提供: viewForSupplementaryElementOfKind

我有一个擦边器,允许用户从一节跳到一节。 现在我滚动到使用scrollToItemAtIndexPath:atScrollPosition:animated:的部分中的第一个项目,但我真正想要滚动collectionView,使该部分的标题是在屏幕的顶部,而不是第一个单元格。 我没有看到一个明显的方法来做到这一点。 你们有没有解决办法?

我想我可以滚动到该部分的第一个项目,然后补充高度加上项目和标题之间的偏移,如果它(有一个方法滚动contentView的坐标点)。 但是,如果有一个更简单的方法,我想知道。

谢谢。

不能使用scrollToItemAtIndexPath:atScrollPosition:animated为此设置scrollToItemAtIndexPath:atScrollPosition:animated

希望他们会在将来添加一个像scrollToSupplementaryElementOfKind:atIndexPath:这样的新方法,但现在,唯一的办法就是直接操作contentOffset

下面的代码展示了如何使用FlowLayout垂直滚动页眉。 您可以为水平滚动执行相同的操作,也可以将其用于其他布局types。

 NSIndexPath *indexPath = ... // indexPath of your header, item must be 0 CGFloat offsetY = [collectionView layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath].frame.origin.y; CGFloat contentInsetY = self.contentInset.top; CGFloat sectionInsetY = ((UICollectionViewFlowLayout *)collectionView.collectionViewLayout).sectionInset.top; [collectionView setContentOffset:CGPointMake(collectionView.contentOffset.x, offsetY - contentInsetY - sectionInsetY) animated:YES]; 

请注意,如果您有非零的contentInset (如在iOS 7中,当滚动视图展开在小节下面时),您需要从offsetY减去它,如图所示。 相同的sectionInset

更新:

代码假定布局处于“有效”状态,因为它使用它来计算偏移量。 当集合视图呈现其内容时,布局就准备好了。

在上面的代码之前调用[_collectionView.collectionViewLayout prepareLayout]可能有助于当您需要滚动尚未呈现的集合视图(来自viewDidLoad说)。 对layoutIfNeeded的调用(如评论中所build议的@Vrasidas)也应该起作用,因为它也准备了布局。

在Swift中的解决scheme,

 let section: = 0 // Top if let cv = self.collectionView { cv.layoutIfNeeded() let indexPath = NSIndexPath(forItem: 1, inSection: section) if let attributes = cv.layoutAttributesForSupplementaryElementOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath) { let topOfHeader = CGPointMake(0, attributes.frame.origin.y - cv.contentInset.top) cv.setContentOffset(topOfHeader, animated:true) } } 

道具基因德丽莎: http : //www.rockhoppertech.com/blog/scroll-to-uicollectionview-header/

 // scroll to selected index NSIndexPath* cellIndexPath = [NSIndexPath indexPathForItem:0 inSection:sectionIndex]; UICollectionViewLayoutAttributes* attr = [self.collectionView.collectionViewLayout layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:cellIndexPath]; UIEdgeInsets insets = self.collectionView.scrollIndicatorInsets; CGRect rect = attr.frame; rect.size = self.collectionView.frame.size; rect.size.height -= insets.top + insets.bottom; CGFloat offset = (rect.origin.y + rect.size.height) - self.collectionView.contentSize.height; if ( offset > 0.0 ) rect = CGRectOffset(rect, 0, -offset); [self.collectionView scrollRectToVisible:rect animated:YES]; 

解决scheme不pipe理的一件事情是如果你钉住节头。 这些方法可以很好地处理未locking的头文件,但是如果您的头文件被locking,当滚动到当前部分上方的部分时,一旦部分头部出现(您的部分的最后一行),它就会停止。 这在某些情况下可能是可取的,但我认为目标是将该部分的顶部放在屏幕的顶部。

在这种情况下,您需要采取上述方法并稍微调整一下。 例如:

 UICollectionView *cv = self.collectionView; CGFloat contentInsetY = cv.contentInset.top; CGFloat offsetY = [cv layoutAttributesForItemAtIndexPath:ip].frame.origin.y; CGFloat sectionHeight = [cv layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:ip].frame.size.height; [cv setContentOffset:CGPointMake(cv.contentOffset.x, offsetY - contentInsetY - sectionHeight) animated:YES]; 

现在,您基本上将您的部分的第一行滚动到可见部分,而不是部分标题的高度。 这将把部分标题放在你想要的顶部的固定标题,所以滚动的方向将不再重要。 我没有用部分插入testing。