【问题标题】:Ios10 UICollectionView prefetching enabled causes selectItemAtIndexPath behave incorrectlyIos10 UICollectionView 预取启用导致 selectItemAtIndexPath 行为不正确
【发布时间】:2017-01-20 04:50:18
【问题描述】:

我试图创建一个包含单元格列表的集合视图。当用户点击一个按钮时,它会随机选择一个单元格。

现在假设只有 10 个单元格。即numberOfItemsInSection委托返回10。 视图控制器是 collectionView 的数据源。集合视图称为myCollectionView。它有一个属性叫selectedIndexPath

所以视图控制器:

@interface ViewController () < UICollectionViewDataSource>
@property (nonatomic, strong) NSIndexPath * selectedIndexPath;
@property (strong, nonatomic) IBOutlet UICollectionView *myCollectionView;
@end

这是我在视图控制器中的随机选择代码:

-(void)chooseRandom{
  NSInteger randomShadeIndex = arc4random_uniform((uint32_t)10);
  NSIndexPath *indexPath = [NSIndexPath indexPathForItem:randomShadeIndex inSection:0];
  self.selectedIndexPath = indexPath;
  [self.myCollectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
}

这是我的视图控制器中的cellForItemAtIndexPath

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
  MyCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MyCell" forIndexPath:indexPath];
  cell.selected = self.selectedIndexPath == indexPath;
  return cell;
}

这是MyCell 中的setSelected: 方法:

- (void)setSelected:(BOOL)selected{
    [super setSelected:selected];

    if (selected){
        self.backgroundColor = [UIColor redColor];
    } else {
        self.backgroundColor = [UIColor greenColor];
    }
}

所以现在当我通过按下按钮拨打chooseRandom 时。如果要选择的随机单元格不可见(不在当前屏幕中),那么很有可能它最终不会在 selectItemAtIndexPath: 期间调用 setSelected:YES。(或者它被调用但设置了单元格。选择为NO 而不是YES)。这意味着生成的屏幕没有选择任何单元格。

有趣的是,当我尝试触摸屏幕时(不选择任何单元格)。它将在要选择的单元格上调用setSelected:。所以我认为selectItemAtIndexPath: 被窃听了。

只有当界面生成器中的prefetching enabled 设置为启用时才会发生这种情况。(这是 ios 10 的默认设置)。

我已经尝试了以下方法来解决这个问题,但它们都不起作用:

  1. chooseRandom末尾添加[self.myCollectionView cellForItemAtIndexPath:indexPath].selected = YES;

  2. scrollToItemAtIndexPath与方法1一起使用,而不是selectItemAtIndexPath:

我认为要么这是一个错误,要么我完全忽略了某些东西。我已经坚持了几个小时,无法弄清楚为什么。现在我认为这很可能是设置了prefetching enabledselectItemAtIndexPath 的错误。

如果您遇到同样的问题,请帮助我并告诉我。谢谢!

编辑: 不知道是否同样的问题。 this link has similar issue but with deselect

【问题讨论】:

  • 尝试调用 scrollToItemAtIndexPath: 和下一行调用 selectItemAtIndexPath:
  • @jayarj 我试过了,但没有用。我也认为它应该在 selectItemAtIndexPath 中滚动。
  • 启用预取时,集合视图委托上的 collectionView(:cellForItemAt:) 方法会在需要单元格时提前调用。为避免视觉外观不一致,请使用 collectionView(:willDisplay:forItemAt:) 委托方法更新单元格以反映视觉状态,例如选择。
  • docs 中的注释说如果你使用 prefetchingEnabled 你必须使用willDisplayCell 来更新你的单元格外观(例如选择状态)

标签: ios objective-c uicollectionview uicollectionviewcell ios10


【解决方案1】:

UICollectionView,就像UITableView,缓存它的单元格。意思是,如果您有 100 个单元格,其中只有 10 个是可见的,它只会创建 10 个单元格并在您滚动时重用它们,在您滚动时设置可见单元格的模型/数据,重用那些不是不再可见(以节省内存)。因此,您无法选择不可见的单元格的原因可能是它尚未创建。

【讨论】:

  • 谢谢,我明白你在说什么。但我不认为这是这里的问题。如果我禁用预取,那么根本没有问题。这只发生在我启用预取时。(在 ios10 中默认启用预取)
【解决方案2】:

如果对你有帮助,请检查一下

可以下载示例项目

https://www.dropbox.com/s/oeo9p1h3e8xfpfj/CollectionView.zip?dl=0?

-(void)chooseRandom{
   NSInteger randomShadeIndex = arc4random_uniform((uint32_t)50);
   NSLog(@"%ld",(long)randomShadeIndex);
   NSIndexPath *indexPath = [NSIndexPath indexPathForItem:randomShadeIndex inSection:0];
   self.selectedIndexPath = indexPath;

   [self.myCollectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:true];
  [_myCollectionView reloadData]; 
}

【讨论】:

  • 感谢您的回复。但我不认为你的回答解决了这个问题。实际上,我认为你的实际上是不正确的,因为可见单元格属性只给出可见单元格,而我想要的是在所有单元格中选择一个随机单元格。并且scrollToItemAtIndexPath已经将它动画设置为true,不需要使用[UIView animateWithDuration]。
  • 它不仅选择可见单元格,self.selectedIndexPath 具有随机索引。当滚动到该选定的索引路径时,将自动选择单元格。尝试下载示例项目并测试...它包含答案
  • 添加这两行代码[self.myCollectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:true]; [_myCollectionView reloadData];
  • 首先,您的原始答案确实不正确。它只选择可见单元格。其次,我不会从互联网上的任何陌生人那里下载任何 zip 文件。第三,我不想调用重载。重新加载基本上会为所有可见单元格调用 cellForItemAtIndexPath 。它确实有效,但它失去了预取给您的所有好处,而且比禁用预取更昂贵。此问题仅在启用预取时发生。我的原始代码在禁用预取的情况下工作得很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-21
  • 2021-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多