53

我目前有一个集合视图,它执行水平分页,其中每个单元格都是全屏的。我想做的是让collectionview在显示时从特定索引开始。

现在我正在使用 scrollToItemAtIndexPath:atScrollPosition:animated: 动画设置为 NO 但它仍然首先加载第一个索引,然后才能滚动到特定项目。看来我只能在 ViewDidAppear 中使用此方法,因此它显示第一个单元格,然后闪烁到我要显示的单元格。我通过隐藏集合视图来隐藏它,直到滚动完成,但这似乎并不理想。

除了我描述的方式之外,有没有更好的方法来做到这一点?

谢谢!

4

11 回答 11

65

所以我用不同的方法解决了这个问题,使用UICollectionViewDelegate方法和一次性Bool

斯威夫特 2:

var onceOnly = false

internal func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
    if !onceOnly {
        let indexToScrollTo = NSIndexPath(forRow: row, inSection: section)
        self.problemListCollectionView.scrollToItemAtIndexPath(indexToScrollTo, atScrollPosition: .Left, animated: false)
        onceOnly = true
    }

}

斯威夫特 3:

  var onceOnly = false

  internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if !onceOnly {
      let indexToScrollTo = IndexPath(item: row, section: section)
      self.problemListCollectionView.scrollToItem(at: indexToScrollTo, at: .left, animated: false)
      onceOnly = true
    }
  }

此代码在任何动画发生之前执行(因此它确实加载到这一点),这比尝试调用 in 更好viewDidAppear,而我在viewWillAppear.

于 2016-02-28T07:21:23.330 回答
21

为了解决这个问题,我部分使用了温室答案。

/// Edit
var startIndex: Int! = 0

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    collectionView.setNeedsLayout()
    collectionView.layoutIfNeeded()

    collectionView.scrollToItemAtIndexPath(
        NSIndexPath(forItem: 0, inSection: startIndex),
        atScrollPosition: .None,
        animated: false)
 }

问题似乎是错误的collectionView大小。设置布局后scrollToItemAtIndexPath会产生所需的结果。

似乎只有在 aCollection View中使用 a时,这个问题才会持续存在UIViewController

于 2015-10-07T10:23:11.390 回答
9

不幸的是,这些现有答案中的每一个都至少部分是错误的,或者没有回答所提出的确切问题。我与一位同事一起解决了这个问题,他没有得到任何这些回复的帮助。

您需要做的就是将没有动画的内容偏移设置为正确的内容偏移,然后调用重新加载数据。(或者如果它还没有被加载,则跳过 reloadData 调用。)如果您不希望创建第一个单元格,您应该在 viewDidLoad 中执行此操作。

此答案假定集合视图水平滚动并且单元格的大小与视图大小相同,但如果您想垂直滚动或单元格大小不同,则概念是相同的。此外,如果您的 CollectionView 有多个部分,则您必须做更多的数学运算来计算内容偏移量,但概念仍然相同。

func viewDidLoad() {
    super.viewDidLoad()
    let pageSize = self.view.bounds.size
    let contentOffset = CGPoint(x: pageSize.width * self.items.count, y: 0)
    self.collectionView.setContentOffset(contentOffset, animated: false)
}
于 2018-04-21T01:21:54.080 回答
7

受其他人启发的更简单的解决方案:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    DispatchQueue.main.async {
        self.collectionView.scrollToItem(at: lastIndexPath, section: 0), at: .centeredHorizontally, animated: false)
    }
}

如果您将代码放在 DispatchQueue.main.async 块中,它将起作用。

于 2018-10-24T11:11:07.603 回答
6

Swift 3.0 经过测试并且可以工作。

var onceOnly = false
    internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        if !onceOnly {
            //set the row and section you need.
            let indexToScrollTo = IndexPath(row: 1, section: indexPath.section)
            self.fotmCollectionView.scrollToItem(at: indexToScrollTo, at: .left, animated: false)
            onceOnly = true
        }
    }
于 2016-10-10T14:23:29.500 回答
3

这对我有用(在 UICollectionViewController 类中):

private var didLayoutFlag: Bool = false

public override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if let collectionView = self.collectionView {
        if !self.didLayoutFlag {
            collectionView.scrollToItemAtIndexPath(self.viewModel.initialIndexPath, atScrollPosition: .None, animated: false)
            self.didLayoutFlag = true
        }
    }
}
于 2016-03-21T15:52:36.640 回答
2

将 indexPath 从第一个 VC 传递到 DidSelectItemAtIndexPath 方法中的集合视图。在集合视图的 viewDidLoad 中,使用scrollToItemAtIndexPath:atScrollPosition:animated:Set animatedtoNOatScrollPositionto方法UICollectionViewScrollPositionNone。像这样:

[self.collectionView scrollToItemAtIndexPath:self.indexPathFromVC atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
于 2014-09-22T08:29:47.083 回答
2

这似乎对我有用:

- (void)viewDidLayoutSubviews
{     
   [self.collectionView layoutIfNeeded];
   NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
   NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
   NSIndexPath *nextItem = [NSIndexPath indexPathForItem:someInt inSection:currentItem.section];

   [self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
于 2015-05-28T18:54:48.743 回答
0

我来到这里遇到了同样的问题,发现在我的情况下,这个问题是导致我的故事板中的 ViewController 被设置为“自由格式”大小。

如果情节提要的尺寸不清楚,我猜 viewWillLayoutSubviews 会在首次加载视图时被调用以计算正确的大小。(我在我的故事板中将我的 viewController 调整为“自由格式”,这样我就可以在我的 collectionView 中的长 tableView 中查看/编辑许多单元格)。

我发现 victor.vasilica 和温室的方法 re: 将 'scrollToRow' 命令放入 viewWillLayoutSubviews 确实可以完美地解决问题。

但是,我还发现,一旦我再次将故事板中的 VC 设置为“固定”大小,问题立即消失了,我可以从 viewWillAppear 设置初始单元格。您的情况可能会有所不同,但这有助于我了解我的情况,我希望我的回答可以帮助其他人了解这个问题。

于 2017-03-22T23:46:36.460 回答
0

willDisplayCell刚刚发现我遇到了同样的问题,并通过在委托调用中添加这段代码来使其工作

private var firstLoad: Bool = true

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    if self.firstLoad {
        let initialIndexPath = <initial index path>
        collectionView.scrollToItem(
            at: initialIndexPath, 
            at: <UICollectionView.ScrollPosition>, 
            animated: false
        )
        self.firstLoad = false
    }
}
于 2020-04-30T13:37:17.560 回答
-1

嘿,我已经解决了 Objective c 问题。我认为这对你很有用。您也可以将 Objective c 转换为 swift 。这是我的代码:

**在我的情况下,单击按钮我激活特定索引,即 3 **

对于垂直

 - (IBAction)Click:(id *)sender {
    NSInteger index=3;
    CGFloat pageHeight = self.collectionView.frame.size.height;
    CGPoint scrollTo = CGPointMake(0, pageHeight * index);
    [self.collectionView setContentOffset:scrollTo animated:YES];
}

对于水平

 - (IBAction)Click:(id *)sender {
    NSInteger index=3;
    CGFloat pageWidth = self.collectionView.frame.size.width;
    CGPoint scrollTo = CGPointMake(pageWidth * index, 0);
    [self.collectionView setContentOffset:scrollTo animated:YES];
}

我希望它可以帮助你。

于 2016-11-29T07:49:46.937 回答