ios 在特定的索引路径启动 UICollectionView
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18087073/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Start UICollectionView at a specific indexpath
提问by Zack
I currently have a collection view that does horizontal paging where each cell is fullscreen. What I want to do is for the collectionview to start at a specific index when it shows.
我目前有一个集合视图,可以在每个单元格全屏的情况下进行水平分页。我想要做的是让 collectionview 在显示时从特定索引开始。
Right now I'm using scrollToItemAtIndexPath:atScrollPosition:animated: with animated set to NO but that still loads the first index first before it can scroll to the specific item. It also seems I can only use this method in ViewDidAppear so it shows the first cell and then blinks to the cell that I want to show. I hide this by hiding the collection view until the scroll has finished but it doesn't seem ideal.
现在我正在使用 scrollToItemAtIndexPath:atScrollPosition:animated: 动画设置为 NO 但它仍然首先加载第一个索引,然后才能滚动到特定项目。似乎我只能在 ViewDidAppear 中使用此方法,因此它显示第一个单元格,然后闪烁到我要显示的单元格。我通过隐藏集合视图直到滚动完成来隐藏它,但这似乎并不理想。
Is there any better way to do this other than the way I described it?
除了我描述的方式之外,还有什么更好的方法可以做到这一点?
Thanks!
谢谢!
回答by sschale
So I solved this a different way, using the UICollectionViewDelegate
method and a one-off Bool
:
所以我用一种不同的方式解决了这个问题,使用UICollectionViewDelegate
方法和一次性Bool
:
Swift 2:
斯威夫特 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
}
}
Swift 3:
斯威夫特 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
}
}
This code is executed before any animation occurs (so it really loads to this point), which is better than attempting to call in viewDidAppear
, and I didn't have success with it in viewWillAppear
.
这段代码在任何动画发生之前执行(所以它真的加载到了这一点),这比尝试调用更好viewDidAppear
,而且我在viewWillAppear
.
回答by victor.vasilica
To solve this problem I partially used the greenhouseanswer.
为了解决这个问题,我部分使用了温室答案。
/// 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)
}
The problem seems to be in the wrong collectionView
size. After setting the layout scrollToItemAtIndexPath
produces the needed result.
问题似乎collectionView
大小不正确。设置布局后scrollToItemAtIndexPath
产生所需的结果。
It also seems that this problem only persists when a Collection View
is used inside a UIViewController
.
似乎这个问题只在 a 在 aCollection View
中使用时才会存在UIViewController
。
回答by Logan Shire
Unfortunately, every single one of these existing answers is at least partly wrong or does not answer the exact question being asked. I worked through this issue with a co-worker who was not helped by any of these responses.
不幸的是,这些现有答案中的每一个都至少有一部分是错误的,或者没有回答所提出的确切问题。我与一位同事一起解决了这个问题,他没有得到任何这些回应的帮助。
All you need to do is set the content offset without animation to the correct content offset and then call reload data. (Or skip the reloadData call if it has not been loaded at all yet.) You should do this in viewDidLoad if you never want the first cell to be created.
您需要做的就是将没有动画的内容偏移设置为正确的内容偏移,然后调用重新加载数据。(或者,如果还没有加载,则跳过 reloadData 调用。)如果您不想创建第一个单元格,则应该在 viewDidLoad 中执行此操作。
This answer assumes the collection view scrolls horizontally and the size of the cells are the same size as the view but the concept is the same if you want to scroll vertically or the cells are a different size. Also if your CollectionView has more than one section you have to do a bit more math to calculate the content offset but the concept is still the same.
此答案假设集合视图水平滚动并且单元格的大小与视图的大小相同,但如果您想垂直滚动或单元格的大小不同,则概念是相同的。此外,如果您的 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)
}
回答by kemicofa ghost
Swift 3.0 tested and works.
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
}
}
回答by Stephen Paul
Pass the indexPath from the first VC to the collection view in the DidSelectItemAtIndexPath method. In viewDidLoad of your collection view, use the method scrollToItemAtIndexPath:atScrollPosition:animated:
Set animated
to NO
and atScrollPosition
to UICollectionViewScrollPositionNone
. Like this:
在 DidSelectItemAtIndexPath 方法中将 indexPath 从第一个 VC 传递到集合视图。在集合视图的 viewDidLoad 中,使用scrollToItemAtIndexPath:atScrollPosition:animated:
Set animated
toNO
和atScrollPosition
to方法UICollectionViewScrollPositionNone
。像这样:
[self.collectionView scrollToItemAtIndexPath:self.indexPathFromVC atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
回答by greenhouse
this seemed to work for me:
这似乎对我有用:
- (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];
}
回答by Andres Wang
A simpler solution inspired by others:
受他人启发的更简单的解决方案:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {
self.collectionView.scrollToItem(at: lastIndexPath, section: 0), at: .centeredHorizontally, animated: false)
}
}
It will work if you put the code inside DispatchQueue.main.async block.
如果您将代码放在 DispatchQueue.main.async 块中,它将起作用。
回答by Nikolay Spassov
Here is what worked for me (in a UICollectionViewController class):
这是对我有用的(在 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
}
}
}
回答by Natalia
I came here having this same issue and found that in my case, this issue was caused my the ViewController in my storyboard being set as 'freeform' size.
我来到这里遇到同样的问题,发现在我的情况下,这个问题是导致我的故事板中的 ViewController 被设置为“自由格式”大小。
I guess viewWillLayoutSubviews gets called to calculate the correct size when the view is first loaded if the storyboard's dimensions leave this unclear. (I had sized my viewController in my storyboard as to be 'freeform' so I could make it very tall to see/edit many cells in long tableView inside my collectionView).
我猜如果故事板的尺寸不清楚,则在首次加载视图时会调用 viewWillLayoutSubviews 来计算正确的大小。(我在我的故事板中将我的 viewController 调整为“自由格式”,这样我就可以让它非常高,以便在我的 collectionView 内的长 tableView 中查看/编辑许多单元格)。
I found that victor.vasilica's & greenhouse's approach re: putting the 'scrollToRow' command in viewWillLayoutSubviews did work perfectly to fix the issue.
我发现 victor.vasilica 和温室的方法是:将 'scrollToRow' 命令放在 viewWillLayoutSubviews 中确实可以完美地解决这个问题。
However, I also found that once I made the VC in my storyboard 'fixed' size again, the issue immediately went away and I was able to set the initial cell from viewWillAppear. Your situation may be different, but this helped me understand what was going on in my situation and I hope my answer might help inform others with this issue.
但是,我还发现,一旦我再次将故事板中的 VC 设置为“固定”大小,问题就会立即消失,我可以从 viewWillAppear 设置初始单元格。你的情况可能有所不同,但这有助于我了解我的情况发生了什么,我希望我的回答可以帮助其他人了解这个问题。
回答by Breno Vinícios
Just found me in the same problem, and make it work by adding this piece of code in willDisplayCell
delegate call
刚刚发现我遇到了同样的问题,并通过在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
}
}