简体   繁体   English

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

[英]Programmatically scroll to a supplementary view within UICollectionView

I am using UICollectionView to display photos in sections.我正在使用UICollectionView以部分显示照片。 Each section has a supplementary view as a header and is supplied via the method: viewForSupplementaryElementOfKind .每个部分都有一个作为标题的补充视图,并通过方法提供: viewForSupplementaryElementOfKind

I have a scrubber on the side that allows the user to jump from section to section.我在侧面有一个洗涤器,允许用户从一个部分跳到另一个部分。 For now I am scrolling to the first item in the section using scrollToItemAtIndexPath:atScrollPosition:animated: , but what I really want is to scroll the collectionView so that that section's header is at the top of the screen, not the first cell.现在我正在使用scrollToItemAtIndexPath:atScrollPosition:animated:滚动到该部分中的第一项,但我真正想要的是滚动 collectionView 以便该部分的标题位于屏幕顶部,而不是第一个单元格。 I do not see an obvious method to do this with.我没有看到一个明显的方法来做到这一点。 Do any of you have a work around?你们中有人有解决办法吗?

I suppose I could scroll to the first item of the section, and then offset that by the supplementary height plus the offset between the items and header if it comes down to that (there is a method for scrolling to point coordinates of the contentView).我想我可以滚动到该部分的第一个项目,然后通过补充高度加上项目和标题之间的偏移量来抵消它,如果它归结为(有一种滚动到 contentView 的点坐标的方法)。 However if there is a simpler way, I'd like to know.但是,如果有更简单的方法,我想知道。

Thanks.谢谢。

You can not use scrollToItemAtIndexPath:atScrollPosition:animated for this.不能scrollToItemAtIndexPath:atScrollPosition:animated使用scrollToItemAtIndexPath:atScrollPosition:animated

Hopefully, they will add a new method like scrollToSupplementaryElementOfKind:atIndexPath: in the future, but for now, the only way is to manipulate the contentOffset directly .希望他们将来会添加一个像scrollToSupplementaryElementOfKind:atIndexPath:这样的新方法,但现在,唯一的方法是直接操作 contentOffset

The code below shows how to scroll header to be on top vertically with FlowLayout.下面的代码显示了如何使用 FlowLayout 将标题滚动到垂直顶部。 You can do the same for horizontal scrolling, or use this idea for other layout 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];

Note that if you have non-zero contentInset (as in iOS 7, when scroll views expand below bars) you need to subtract it from the offsetY , as shown.请注意,如果您有非零的contentInset (如在 iOS 7 中,当滚动视图在条形下方展开时),您需要从offsetY减去它,如图所示。 Same for sectionInset .sectionInset相同。

Update:更新:

The code assumes that the layout is in prepared, "valid" state because it uses it to calculate the offset.该代码假定布局处于准备好的“有效”状态,因为它使用它来计算偏移量。 The layout is prepared when the collection view presents its content.当集合视图呈现其内容时,布局就准备好了。

The call to [_collectionView.collectionViewLayout prepareLayout] before the code above may help when you need to scroll the collection view which is not yet presented (from viewDidLoad say).当您需要滚动尚未呈现的集合视图时,在上面的代码之前调用[_collectionView.collectionViewLayout prepareLayout]可能会有所帮助(从viewDidLoad说)。 The call to layoutIfNeeded (as @Vrasidas suggested in comments) should work too because it also prepares the layout.layoutIfNeeded的调用(如@Vrasidas 在评论中建议的那样)也应该起作用,因为它也准备了布局。

Solution in Swift, 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)
    }
}

Props to Gene De Lisa: http://www.rockhoppertech.com/blog/scroll-to-uicollectionview-header/ Gene De Lisa 的道具: 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];

One thing the solutions don't manage is if you are pinning section headers.解决方案无法管理的一件事是,您是否正在固定节标题。 The methods work fine with unpinned headers, but if your headers are pinned, while scrolling to a section above the current section, it will stop once the section header appears (which will be for the bottom row of your section).这些方法适用于未固定的标题,但如果您的标题已固定,则在滚动到当前部分上方的部分时,一旦出现部分标题(这将用于您部分的底行),它将停止。 That may be desirable in some cases but I think the goal is to put the top of the section at the top of the screen.在某些情况下这可能是可取的,但我认为目标是将部分的顶部放在屏幕的顶部。

In which case you need to take the methods above and adjust them a bit.在这种情况下,您需要采用上述方法并对其进行一些调整。 For instance:例如:

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

Now you are basically scrolling the first row of your section to visible, less the height of its section header.现在,您基本上将部分的第一行滚动到可见,减去其部分标题的高度。 This will put the section header on the top where you want it with pinned headers so the direction of the scroll won't matter anymore.这会将节标题放在您想要的顶部,并带有固定标题,因此滚动方向不再重要。 I didn't test with section insets.我没有用部分插图进行测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 具有自定义布局的UICollectionView - 以编程方式添加补充视图的方式/位置? - UICollectionView with custom layout - how/where to add a supplementary view programmatically? 将 UICollectionView 滚动到部分标题视图 - Scroll UICollectionView to section header view 如何使补充视图在 UICollectionView 中浮动,就像节标题在 UITableView 普通样式中所做的那样 - How to make Supplementary View float in UICollectionView as Section Headers do in UITableView plain style UICollectionView标头视图以编程方式创建并添加? - UICollectionView header view create programmatically and add? 如何在collectionView中重新加载补充视图 - how to reload supplementary view in collectionView 如何使用UIImageView和UICollectionView创建布局,并且集合视图在滚动时更改高度? - How to create Layout with UIImageView and UICollectionView and collection view changes height on scroll? 有没有办法以编程方式滚动到UIWebView中的PDF页面? - Is there a way to programmatically scroll to a PDF page within a UIWebView? 以编程方式滚动表格视图并调整滚动时间? - Programmatically scrolling table view and adjusting scroll time? 以编程方式在滚动视图外部检测触摸 - Detecting touches outside a scroll view programmatically 在滚动视图中有滚动视图? 一个页面上有多个表? - Having a scroll view within a scroll view? Multiple tables on a page?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM