我想让UICollectionView对特定项目进行动画滚动。
大部分时间都可以使用,但偶尔我尝试滚动到的项目最终不会显示。
- (void)onClick {
// (Possibly recompute the _items array.)
NSInteger target_idx = // (...some valid index of _items)
NSIndexPath *item_idx = [NSIndexPath indexPathForItem:target_idx inSection:0];
[self scrollToItem:item_idx];
}
- (void)scrollToItem:(NSIndexPath*)item_idx {
// Make sure our view is up-to-date with the data we want to show.
NSInteger num_items = [self.collection_view numberOfItemsInSection:0];
if (num_items != _items.count) {
[self.collection_view reloadData];
}
[self.collection_view
scrollToItemAtIndexPath:item_idx
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:YES];
}
self.collection_view
是一个UICollectionView,由一行项目组成,具有标准流程布局和水平滚动功能。reloadData
,因为自从UICollectionView上次显示它以来_items
可能已经发生了变化。animated:NO
,那么一切都按预期工作。indexPathsForVisibleItems
的滚动后调用显示UICollectionView 认为目标项目不可见。为什么有时会无声地滚动到某个项目的想法会失败?
更新:问题似乎来自重新加载和快速连续滚动;如果没有重新加载,则滚动操作符合预期。在加载新数据后是否有滚动到项目的习语?
答案 0 :(得分:3)
在@NicholasHart的帮助下,我想我明白了这个问题。
只要重新加载使集合更大,尝试reloadData
然后执行动画滚动到新位置就有意义(并且似乎有效)。
然而,当重新加载收缩集合时,动画滚动的起点可能不再存在。这使得动画很麻烦。
例如,如果您开始向右滚动视图(以便最右边的项目可见),然后重新加载并丢失一半的项目,则不清楚动画的起点应该是什么。在这种情况下尝试制作动画滚动会导致无操作或跳转到非常奇怪的位置。
一个看起来相当不错的解决方案是仅在集合变大的情况下进行动画处理:
- (void)scrollToItem:(NSIndexPath*)item_idx {
// Make sure our view is up-to-date with the data we want to show.
NSInteger old_num_items = [self.collection_view numberOfItemsInSection:0];
NSInteger new_num_items = _items.count;
if (old_num_items != new_num_items) {
[self.collection_view reloadData];
}
// Animating if we're getting smaller doesn't really make sense, and doesn't
// seem to be supported.
BOOL is_expanding = new_num_items >= old_num_items;
[self.collection_view
scrollToItemAtIndexPath:item_idx
atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
animated:is_expanding];
}
答案 1 :(得分:0)
这对我有用:
[UIView performWithoutAnimation:^{
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadData];
} completion:^(BOOL finished) {
if (finished) {
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:messages.count - 1 inSection:0]
atScrollPosition:UICollectionViewScrollPositionBottom
animated:NO];
}
}];
}];