在特定索引路径处启动UICollectionView

时间:2013-08-06 17:51:05

标签: ios paging uicollectionview

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

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

除了我描述的方式之外,还有更好的方法吗?

谢谢!

11 个答案:

答案 0 :(得分:52)

所以我使用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
    }
  }

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

答案 1 :(得分:15)

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

/// 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生成所需的结果。

Collection View内使用UIViewController时,似乎只会出现此问题。

答案 2 :(得分:5)

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

答案 3 :(得分:4)

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

您需要做的就是将没有动画的内容偏移设置为正确的内容偏移,然后调用重新加载数据。 (或者如果尚未加载,则跳过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)
}

答案 4 :(得分:3)

这似乎对我有用:

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

答案 5 :(得分:2)

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

[self.collectionView scrollToItemAtIndexPath:self.indexPathFromVC atScrollPosition:UICollectionViewScrollPositionNone animated:NO];

答案 6 :(得分:2)

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

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块中,它将起作用。

答案 7 :(得分:1)

这对我有用(在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
        }
    }
}

答案 8 :(得分:0)

嘿,我已经解决了目标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];
}

我希望它可以帮到你。

答案 9 :(得分:0)

我来到这里有同样的问题,发现在我的情况下,这个问题导致我的故事板中的ViewController被设置为' freeform'尺寸。

我猜想,如果故事板的尺寸不明确,那么在首次加载视图时会调用viewWillLayoutSubviews来计算正确的大小。 (我在我的故事板中调整了viewController的大小,因为它是自由形式的,所以我可以在我的collectionView中查看/编辑long tableView中的许多单元格。

我发现victor.vasilica& s&温室的方法re:把'scrollToRow' viewWillLayoutSubviews中的命令确实可以完美地解决问题。

然而,我还发现,一旦我在故事板中制作了VC,就会修复'大小再次,问题立即消失,我能够从viewWillAppear设置初始单元格。你的情况可能会有所不同,但这有助于我理解我的情况发生了什么,我希望我的回答可以帮助其他人解决这个问题。

答案 10 :(得分: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
    }
}