将 UICollectionView 滚动到部分标题视图

问题描述 投票:0回答:9

下面的代码滚动到

UICollectionView
中的右侧单元格,但在我的例子中,节标题视图隐藏在
UINavigationBar
后面。我相信我应该使用
scrollRectToVisible
来代替,我的问题是,当给定
CGRect
中的
numberOfRows
是可变的时,计算
section
(y 位置)的正确方法是什么。

- (void)scrollToPricing:(NSUInteger)row {

    [self.collectionView scrollToItemAtIndexPath:
      [NSIndexPath indexPathForItem:0 
                          inSection:row] 
                   atScrollPosition:UICollectionViewScrollPositionTop 
                           animated:YES];
}
ios iphone uicollectionview
9个回答
36
投票

似乎所有答案都过于复杂。这对我有用:

let attributes = self.collectionView.collectionViewLayout.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: NSIndexPath(forItem: 0, inSection: section))

self.collectionView.setContentOffset(CGPointMake(0, attributes!.frame.origin.y - self.collectionView.contentInset.top), animated: true)

斯威夫特5:

if let attributes = collectionView.collectionViewLayout.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(item: 0, section: section)) {
    collectionView.setContentOffset(CGPoint(x: 0, y: attributes.frame.origin.y - collectionView.contentInset.top), animated: true)
}

11
投票

我想这可能对你有帮助

UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath];

然后您可以通过

attributes.frame

访问该位置

11
投票

基于

@pixelfreak
答案

Swift 4.2
+
iOS 11 Safe Area
支持(适用于 iPhone X 及以上版本)

if let attributes = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(item: 0, section: section)) {
    var offsetY = attributes.frame.origin.y - collectionView.contentInset.top
    if #available(iOS 11.0, *) {
        offsetY -= collectionView.safeAreaInsets.top
    }
    collectionView.setContentOffset(CGPoint(x: 0, y: offsetY), animated: true) // or animated: false
}

快乐编码


5
投票

首先,获取该部分中标题的框架:

- (CGRect)frameForHeaderForSection:(NSInteger)section {
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:section];
    UICollectionViewLayoutAttributes *attributes = [self.collectionView layoutAttributesForItemAtIndexPath:indexPath];
    CGRect frameForFirstCell = attributes.frame;
    CGFloat headerHeight = [self collectionView:_collectionView layout:_layout referenceSizeForHeaderInSection:section].height;
    return CGRectOffset(frameForFirstCell, 0, -headerHeight);
}

注意:我只是为

1
设置了
indexPath.item
值。您可能需要将其更改为适合您的实现的内容。

然后,将

UIScrollView
滚动到标题顶部的点:

- (void)scrollToTopOfSection:(NSInteger)section animated:(BOOL)animated {
    CGRect headerRect = [self frameForHeaderForSection:section];
    CGPoint topOfHeader = CGPointMake(0, headerRect.origin.y - _collectionView.contentInset.top);
    [_collectionView setContentOffset:topOfHeader animated:animated];
}

注意:您必须减去

contentInset
,否则它将被丢弃,并且您的滚动视图将滚动到状态栏和/或导航栏后面。


2
投票
// [myCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:index_of_sec] atScrollPosition:UICollectionViewScrollPositionTop animated:YES];

Below code will fix your problem, as i have faced same issue and used this solution developed by me instead of above commented code.

UICollectionViewLayoutAttributes *attributes = [myCollectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:index_of_sec]];
        CGRect rect = attributes.frame;
        [myCollectionView setContentOffset:CGPointMake(myCollectionView.frame.origin.x, rect.origin.y - HEIGHT_OF_YOUR_HEADER) animated:YES];

2
投票

最简单的方法是使用 section header

frame.origin.x
frame.origin.y
,然后将 section header
height
item
height
添加到
CGRect
来滚动到。

let sectionHeaderAttributes: UICollectionViewLayoutAttributes = self.collectionView.layoutAttributesForItem(at: scrollToIndexPath)!;
let itemAttributes: UICollectionViewLayoutAttributes = self.collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionElementKindSectionHeader, at: scrollToIndexPath)!;

let combinedFrame: CGRect = CGRect(x: sectionHeaderAttributes.frame.origin.x, y: sectionHeaderAttributes.frame.origin.y, width: sectionHeaderAttributes.frame.width, height: sectionHeaderAttributes.frame.height + itemAttributes.frame.height);

collectionView.scrollRectToVisible(combinedFrame, animated: false);

1
投票
// 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];

1
投票

我发现接受的答案不再正常工作(2个标题粘在一起),特别是当集合视图必须向上滚动时(向下仍然可以正常工作)。

以下代码在任一方向上都可以完美运行:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
UICollectionViewLayoutAttributes *headerAttribs = [iconsCV layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
UICollectionViewLayoutAttributes *attribs = [iconsCV layoutAttributesForItemAtIndexPath:indexPath];
CGPoint topOfHeader = CGPointMake(0, attribs.frame.origin.y -collectionV.contentInset.top -headerAttribs.bounds.size.height);
[collectionV setContentOffset:topOfHeader animated:YES];

1
投票

最初面临类似的问题,直到我意识到

UICollectionView.ScrollPosition
可用于在集合视图框架中定位标题。

您只需使用 UICollectionViewScrollPositionCenteredVertically 选项即可使标题在集合视图框架的中心可见。

这是我在 Swift 4.2 中实现这一目标的方法:

let scrollableSection = IndexPath.init(row: 0, section: indexPath.item)

emojiCollectionView.scrollToItem(at: scrollableSection, at: .centeredVertically, animated: true)
© www.soinside.com 2019 - 2024. All rights reserved.