在特定索引路径启动UICollectionView

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

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

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

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

ios pagination uicollectionview
11个回答
67
投票

所以我用不同的方式解决了这个问题,使用

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
中没有成功。


21
投票

为了解决这个问题,我部分使用了 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
时,此问题才会持续存在。


11
投票

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

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

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 块中就会起作用。


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

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

2
投票

将indexPath从第一个VC传递到DidSelectItemAtIndexPath方法中的集合视图。在集合视图的 viewDidLoad 中,使用方法

scrollToItemAtIndexPath:atScrollPosition:animated:
animated
设置为
NO
,将
atScrollPosition
设置为
UICollectionViewScrollPositionNone
。像这样:

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

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

0
投票

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

我猜想,如果故事板的尺寸不清楚,那么首次加载视图时,会调用 viewWillLayoutSubviews 来计算正确的大小。 (我在故事板中将 viewController 的大小设置为“自由形式”,这样我就可以将其设置得非常高,以便在我的 collectionView 内的长 tableView 中查看/编辑许多单元格)。

我发现 victor.vasilica 和温室的方法 re: put the 'scrollToRow' command in viewWillLayoutSubviews 确实完美地解决了这个问题。

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


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

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

希望对您有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.