23

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

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

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

谢谢。

4

4 回答 4

38

不能scrollToItemAtIndexPath:atScrollPosition:animated这个。

希望他们将来会添加一个新方法scrollToSupplementaryElementOfKind:atIndexPath:,但目前唯一的方法是直接操作 contentOffset

下面的代码显示了如何使用 FlowLayout 将标题垂直滚动到顶部。您可以对水平滚动执行相同的操作,或将此想法用于其他布局类型。

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(正如评论中建议的@Vrasidas)也应该起作用,因为它还准备了布局。

于 2013-08-21T17:51:25.767 回答
7

Swift 中的解决方案,

let section: Int = 0 // Top

if let cv = self.collectionView {

    cv.layoutIfNeeded()

    let indexPath = IndexPath(row: 1, section: section)
    if let attributes =  cv.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath) {

        let topOfHeader = CGPoint(x: 0, y: attributes.frame.origin.y - cv.contentInset.top)
        cv.setContentOffset(topOfHeader, animated: true)
    }
}

给 Gene De Lisa 的道具:http ://www.rockhoppertech.com/blog/scroll-to-uicollectionview-header/

于 2016-04-07T20:30:27.510 回答
2
// 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];
于 2015-01-07T07:15:40.483 回答
2

解决方案无法管理的一件事是,如果您要固定部分标题。这些方法适用于未固定的标题,但如果您的标题已固定,则在滚动到当前部分上方的部分时,一旦部分标题出现(这将是您部分的底行),它将停止。在某些情况下这可能是可取的,但我认为目标是将部分的顶部放在屏幕的顶部。

在这种情况下,您需要采用上述方法并进行一些调整。例如:

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];

现在您基本上将您的部分的第一行滚动到可见,减去其部分标题的高度。这会将部分标题放在您想要的顶部,并带有固定标题,这样滚动的方向就不再重要了。我没有使用部分插图进行测试。

于 2016-09-01T21:32:21.883 回答