UICollectionView中的动画滚动到项目并不总是有效

时间:2013-07-19 17:20:58

标签: ios objective-c scroll uicollectionview animated

问题

我想让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 认为目标项目不可见

为什么有时会无声地滚动到某个项目的想法会失败?


更新:问题似乎来自重新加载和快速连续滚动;如果没有重新加载,则滚动操作符合预期。在加载新数据后是否有滚动到项目的习语?

2 个答案:

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