33

我试图弄清楚当屏幕首次加载时如何一直滚动到 UICollectionView 的底部。当状态栏被触摸时,我可以滚动到底部,但我希望能够在视图加载时自动执行此操作。如果我想在触摸状态栏时滚动到底部,则以下内容可以正常工作。

- (BOOL)scrollViewShouldScrollToTop:(UITableView *)tableView
{
NSLog(@"Detect status bar is touched.");
[self scrollToBottom];
return NO;
}

-(void)scrollToBottom
{//Scrolls to bottom of scroller
 CGPoint bottomOffset = CGPointMake(0, collectionViewReload.contentSize.height -     collectionViewReload.bounds.size.height);
 [collectionViewReload setContentOffset:bottomOffset animated:NO];
 }

我尝试在 viewDidLoad 中调用 [self scrollToBottom]。这是行不通的。关于视图加载时如何滚动到底部的任何想法?

4

9 回答 9

37

我发现在 viewWillAppear 中没有任何效果。我只能让它在 viewDidLayoutSubviews 中工作:

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:endOfModel inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
于 2014-08-16T00:21:07.270 回答
19

只是为了详细说明我的评论。

viewDidLoad 在元素可见之前被调用,因此某些 UI 元素不能很好地操作。诸如在工作中移动按钮但处理子视图通常不会(如滚动 CollectionView)。

当在 viewWillAppear 或 viewDidAppear 中调用时,这些操作中的大多数都会发挥最佳效果。这是 Apple 文档中的一个例外,它指出了在覆盖这些方法中的任何一个时要做的重要事情:

您可以覆盖此方法以执行与呈现视图相关的其他任务。如果你重写了这个方法,你必须在你的实现中调用 super 。

super 调用通常在自定义实现之前调用。(所以覆盖方法内的第一行代码)。

于 2013-02-08T00:43:18.793 回答
11

所以有一个类似的问题,这是另一种不使用 scrollToItemAtIndexPath的方法

仅当内容大于视图框架时,才会滚动到底部。

使用 scrollToItemAtIndexPath 可能更好,但这只是另一种方法。

CGFloat collectionViewContentHeight = myCollectionView.contentSize.height;
CGFloat collectionViewFrameHeightAfterInserts = myCollectionView.frame.size.height - (myCollectionView.contentInset.top + myCollectionView.contentInset.bottom);

if(collectionViewContentHeight > collectionViewFrameHeightAfterInserts) {
   [myCollectionView setContentOffset:CGPointMake(0, myCollectionView.contentSize.height - myCollectionView.frame.size.height) animated:NO];
}
于 2015-10-21T21:06:59.907 回答
6

斯威夫特 3 示例

let sectionNumber = 0
self.collectionView?.scrollToItem(at: //scroll collection view to indexpath
                                  NSIndexPath.init(row:(self.collectionView?.numberOfItems(inSection: sectionNumber))!-1, //get last item of self collectionview (number of items -1)
                                                   section: sectionNumber) as IndexPath //scroll to bottom of current section
                                , at: UICollectionViewScrollPosition.bottom, //right, left, top, bottom, centeredHorizontally, centeredVertically
                                animated: true)
于 2016-11-11T18:05:59.040 回答
4

获取最后一项的索引路径。然后...

- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated
于 2013-06-01T15:39:33.163 回答
3

对我来说,我找到了下一个解决方案:

在 CollectionView 中调用 reloadData,并使 main 上的 dcg 滚动。

 __weak typeof(self) wSelf = self;

 [wSelf.cv reloadData];
 dispatch_async(dispatch_get_main_queue(), ^{
 NSLog(@"HeightGCD:%@", @(wSelf.cv.contentSize.height));
 [wSelf.cv scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:50 inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:YES];
 });
于 2015-10-23T09:56:26.357 回答
2

这些都不适合我,我最终得到了这个,它可以在任何滚动视图上工作

extension UIScrollView {
    func scrollToBottom(animated: Bool) {
        let y = contentSize.height - 1
        let rect = CGRect(x: 0, y: y + safeAreaInsets.bottom, width: 1, height: 1)
        scrollRectToVisible(rect, animated: animated)
    }
}
于 2021-01-14T22:24:23.287 回答
2

问题很可能是即使您的收藏视图在屏幕上,它也可能没有实际的contentSize.

如果您滚动viewDidAppear,您将有一个contentSize,但您的 scollectionview 将在滚动之前简要显示内容。

问题viewDidLayoutSubviews是它被多次调用,所以你需要添加一个丑陋的布尔值来限制滚动。

我发现的最佳解决方案是强制布局在视图中出现。

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // force layout before scrolling to most recent
    collectionView.layoutIfNeeded()
    // now you can scroll however you want
    // e.g. scroll to the right
    let offset = collectionView.contentSize.width - collectionView.bounds.size.width
    collectionView.setContentOffSet(CGPoint(x: offset, y: 0), animated: animated)
}
于 2019-10-17T13:42:28.260 回答
0

考虑是否可以performBatchUpdates这样使用:

private func reloadAndScrollToItem(at index: Int, animated: Bool) {
    collectionView.reloadData()
    collectionView.performBatchUpdates({
        self.collectionView.scrollToItem(at: IndexPath(item: index, section: 0),
                                         at: .bottom,
                                         animated: animated)
    }, completion: nil)
}

如果index是集合视图数据源中最后一项的索引,它将一直滚动到底部。

于 2020-10-30T12:00:45.547 回答