我目前有一个集合视图,它可以进行水平分页,其中每个单元格都是全屏的。我想要做的是让 CollectionView 在显示时从特定索引开始。
现在我正在使用scrollToItemAtIndexPath:atScrollPosition:animated:将animated设置为NO,但仍然首先加载第一个索引,然后才能滚动到特定项目。看来我只能在 ViewDidAppear 中使用此方法,因此它显示第一个单元格,然后闪烁到我想要显示的单元格。我通过隐藏集合视图来隐藏它,直到滚动完成,但它看起来并不理想。
除了我描述的方式之外,还有其他更好的方法吗?
所以我用不同的方式解决了这个问题,使用
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
中没有成功。
为了解决这个问题,我部分使用了 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
时,此问题才会持续存在。
不幸的是,这些现有答案中的每一个都至少有部分是错误的,或者没有回答所提出的确切问题。我和一位同事一起解决了这个问题,但这些回复都没有给他带来帮助。
您需要做的就是将没有动画的内容偏移设置为正确的内容偏移,然后调用重新加载数据。 (或者如果尚未加载,则跳过 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)
}
受其他人启发的更简单的解决方案:
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 块中就会起作用。
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
}
}
这对我有用(在 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
}
}
}
将indexPath从第一个VC传递到DidSelectItemAtIndexPath方法中的集合视图。在集合视图的 viewDidLoad 中,使用方法
scrollToItemAtIndexPath:atScrollPosition:animated:
将 animated
设置为 NO
,将 atScrollPosition
设置为 UICollectionViewScrollPositionNone
。像这样:
[self.collectionView scrollToItemAtIndexPath:self.indexPathFromVC atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
这似乎对我有用:
- (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];
}
我来到这里遇到了同样的问题,发现在我的情况下,这个问题是由于我的故事板中的 ViewController 被设置为“自由格式”大小造成的。
我猜想,如果故事板的尺寸不清楚,那么首次加载视图时,会调用 viewWillLayoutSubviews 来计算正确的大小。 (我在故事板中将 viewController 的大小设置为“自由形式”,这样我就可以将其设置得非常高,以便在我的 collectionView 内的长 tableView 中查看/编辑许多单元格)。
我发现 victor.vasilica 和温室的方法 re: put the 'scrollToRow' command in viewWillLayoutSubviews 确实完美地解决了这个问题。
但是,我还发现,一旦我再次将故事板中的 VC 设置为“固定”大小,问题立即消失,并且我能够从 viewWillAppear 设置初始单元格。 您的情况可能有所不同,但这帮助我了解了我的情况,我希望我的回答可以帮助其他人了解这个问题。
刚刚发现我遇到了同样的问题,并通过在
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
}
}
嘿我已经解决了 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];
}
希望对您有帮助。