【发布时间】:2013-04-05 19:40:35
【问题描述】:
在加载集合视图之前,用户设置集合视图数组中的图像数量。所有单元格都不适合屏幕。我有 30 个单元格,但屏幕上只有 6 个。
问题:如何在加载 UICollectionView 时自动滚动到具有所需图像的单元格?
【问题讨论】:
标签: ios uicollectionview
在加载集合视图之前,用户设置集合视图数组中的图像数量。所有单元格都不适合屏幕。我有 30 个单元格,但屏幕上只有 6 个。
问题:如何在加载 UICollectionView 时自动滚动到具有所需图像的单元格?
【问题讨论】:
标签: ios uicollectionview
新的、已编辑的答案:
将此添加到viewDidLayoutSubviews
SWIFT
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let indexPath = IndexPath(item: 12, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: [.centeredVertically, .centeredHorizontally], animated: true)
}
一般情况下.centerVertically是这样的
ObjC
-(void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:12 inSection:0];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically | UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}
适用于旧 iOS 的旧答案
将此添加到viewWillAppear:
[self.view layoutIfNeeded];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
【讨论】:
indexPath:[NSIndexPath indexPathForItem:numberOfTheObject inSection:sectionNumber]
我完全同意上面的答案。唯一的问题是,对我来说,解决方案是在 viewDidAppear 中设置代码
viewDidAppear
{
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
}
当我使用 viewWillAppear 时,滚动不起作用。
【讨论】:
我发现在viewWillAppear 中滚动可能无法可靠地工作,因为集合视图尚未完成其布局;您可能会滚动到错误的项目。
我还发现滚动viewDidAppear 会导致未滚动视图的瞬间闪烁可见。
而且,如果您每次滚动通过viewDidLayoutSubviews,用户将无法手动滚动,因为某些集合布局会在您每次滚动时导致子视图布局。
以下是我发现的可靠方法:
目标 C:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// If we haven't done the initial scroll, do it once.
if (!self.initialScrollDone) {
self.initialScrollDone = YES;
[self.collectionView scrollToItemAtIndexPath:self.myInitialIndexPath
atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
}
}
斯威夫特:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if !self.initialScrollDone {
self.initialScrollDone = true
self.testNameCollectionView.scrollToItem(at:selectedIndexPath, at: .centeredHorizontally, animated: true)
}
}
【讨论】:
initialScrollDone 标志,因为此方法将被多次调用,并且如果您多次调用 scrollToItemAtIndexPath: 似乎会使 collectionView 无法滚动(iOS 模拟器 iPhone 5/iOS 8)跨度>
[self.collectionView layoutIfNeeded];,当您在viewDidLoad 中执行此操作时也可以使用。
这似乎对我有用,它类似于另一个答案,但有一些明显的区别:
- (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];
}
【讨论】:
斯威夫特:
your_CollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)
斯威夫特 3
let indexPath = IndexPath(row: itemIndex, section: sectionIndex)
collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.right, animated: true)
滚动位置:
UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically
【讨论】:
您可以使用 GCD 将滚动分派到 viewDidLoad 中的主运行循环的下一次迭代中以实现此行为。滚动将在集合视图显示在屏幕上之前执行,因此不会闪烁。
- (void)viewDidLoad {
dispatch_async (dispatch_get_main_queue (), ^{
NSIndexPath *indexPath = YOUR_DESIRED_INDEXPATH;
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
});
}
【讨论】:
这里的所有答案 - 黑客。我找到了在 relaodData 之后在某处滚动集合视图的更好方法:
子类集合视图布局您使用什么布局,覆盖方法 prepareLayout,在超级调用之后设置您需要的任何偏移量。
例如:https://stackoverflow.com/a/34192787/1400119
【讨论】:
我建议在collectionView: willDisplay: 中执行此操作,然后您可以确定集合视图委托提供了一些东西。
这是我的例子:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
/// this is done to set the index on start to 1 to have at index 0 the last image to have a infinity loop
if !didScrollToSecondIndex {
self.scrollToItem(at: IndexPath(row: 1, section: 0), at: .left, animated: false)
didScrollToSecondIndex = true
}
}
【讨论】:
作为上述的替代方案。 数据加载后调用:
斯威夫特
collectionView.reloadData()
collectionView.layoutIfNeeded()
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .right)
【讨论】: