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

时间:2013-04-26 22:39:52

标签: iphone ios ipad uicollectionview

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

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

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

感谢。

4 个答案:

答案 0 :(得分: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)也应该有效,因为它也准备了布局。

答案 1 :(得分:6)

Swift解决方案,

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)
    }
}

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

答案 2 :(得分: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];

答案 3 :(得分:1)

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

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

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

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