【问题标题】:UICollectionView jumpy scrollingUICollectionView 跳跃滚动
【发布时间】:2015-03-20 11:28:43
【问题描述】:

我正在尝试创建一个可以容纳不同大小的“视图”等的界面。为此,我正在使用带有这些单元格的 UICollectionView:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    Card *card = [[[usermanager getSelectedUser] getCards] objectAtIndex:indexPath.item];
    UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cardCell" forIndexPath:indexPath];
    [cell addSubview:card];

    [cell.layer setBorderColor:[UIColor redColor].CGColor];
    [cell.layer setBorderWidth:1.0f];
    [cell.layer setMasksToBounds:NO];
    return cell;
}

一切似乎都很好,直到卡片数量变得太大而我不得不滚动。当我滚动后抬起手指时,视图会稍微跳跃。我还遇到了一些其他奇怪的 UI 问题。从我读过的内容来看,这与滚动期间重新加载单元格有关。防止这种情况的正确方法是什么?

注意内容是动态的,这一点非常重要。用户应该能够在运行时添加和移除卡片。

谢谢

【问题讨论】:

  • [[usermanager getSelectedUser] getCards] 执行需要多长时间?
  • 你有自己的布局吗?如果是,请确保您继承UICollectionViewLayout 并在使布局无效时使用UICollectionViewLayoutInvalidationContext
  • @Dennis 我正在使用 CHTCollectionViewWaterFallLayout
  • @trojanfoe 大约 66.0 毫秒
  • @BlackMagic 你是怎么做到的?我正在开发我的应用程序的 iPad 版本,并且在 iPad air 1st gen 上只能获得大约 30-40 fps。使用 cpu 分析器(集合布局除外)没有任何明显的显示。

标签: ios objective-c scroll uicollectionview uicollectionviewcell


【解决方案1】:

您在评论中声明您正在使用CHTCollectionViewWaterFallLayout。 我自己在一个应用程序中使用过,从性能的角度来看,它不是最优的(我现在检查了源代码,关键点还是一样的)。我必须进行几次调整才能使其顺利进行。

首先,如果您的目标是 iOS 8 及更高版本UICollectionView 已进行了巨大改进,如果可能,您绝对应该确保使用它。 2014 WWDC 视频What's New in Table and Collection Views 为您提供了一个很好的概述。关键是iOS 8在UICollectionViewLayoutInvalidationContext中增加了三个新方法:

- invalidateItemsAtIndexPaths:
- invalidateSupplementaryElementsOfKind:atIndexPaths:
- invalidateDecorationElementsOfKind:atIndexPaths:

将这些方法与UICollectionViewLayout invalidationContextForBoundsChange: 一起使用,您可以极大地缩小您的布局需要处理的项目数量。这将为您提供最佳性能。

如果像我一样,您还需要以 iOS 7 为目标,事情就会变得更加复杂。您可以改进布局中的两种关键方法:

  • 首先,shouldInvalidateLayoutForBoundsChange: 调查更改的边界并确保仅在绝对必要时才使整个布局无效。
  • 第二个,prepareLayout,只有在整个布局失效时才应该调用它。

在我的例子中,我必须添加浮动标题,所以我在shouldInvalidateLayoutForBoundsChange: 中设置了一个属性shouldInvalidateAll,我检查了prepareLayout 以了解我是否真的需要从头开始准备布局。

要让它顺利进行实际上并不容易(但可能),但我希望这为您的版本改进奠定了一个起点。

【讨论】:

    【解决方案2】:

    您可以对集合视图单元进行子类化,并在创建时执行所有层初始化,而不是在每次重用时执行。

    另外,当重复使用这样的单元格时,您应该检查现有单元格是否已经添加了Card。重用时,afaik iOS 不会自动删除添加的子视图(因此对于重用的单元格 addSubview 可以使用不同的卡片执行多次,您可以使用视图调试检查这一点)。

    您还可以延迟加载单元格内容。

    【讨论】:

    • 问题是:所有内容都是动态的。用户可以在运行时添加或移除卡片
    • @BlackMagic 你只需要确保正确地重复使用这些单元格。也许在卡片子视图中添加一个标签,每次添加新卡片之前,只需删除旧卡片(如果存在)。 [[cell viewWithTag:CARDTAG] removeFromSuperview]
    • 我不确定你是否理解我想要做什么。每个单元格都有一张卡片。并且单元格的数量可以变化,以及单个单元格的大小
    • @BlackMagic 我明白了,我只是说你可以消除一些多次加载的视图。对于图像,延迟加载仍然是一种选择。
    【解决方案3】:

    我可以从您的代码中了解到,在每个 cellForItemAtIndexPath 调用中,您都在制作一个新的卡片对象并将其添加为单元格上的子视图。

    您实际上并没有使用重用单元的力量。 尝试在单元格上添加 UI 元素(故事板或您正在使用的 xib)。然后根据索引路径设置这些元素的值。这将消除滚动的滞后。

    同时导入<QuartzCore/QuartzCore.h>

    [cell.layer setShadowPath:[[UIBezierPath
                                bezierPathWithRect:self.bounds] CGPath]];
    
    [cell.layer setBorderColor:[UIColor redColor].CGColor];    
    [cell.layer setBorderWidth:1.0f];
    [cell.layer setMasksToBounds:NO];
    

    【讨论】:

    • 问题是我使用的是动态内容。用户应该能够随意添加和删除卡片
    【解决方案4】:

    我有点想通了。我的一些卡片包含图像,每次我滚动系统都会从内存中重新加载所有这些图像。这使得滚动相对缓慢且不稳定。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      • 2017-07-01
      • 1970-01-01
      • 2014-03-26
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      相关资源
      最近更新 更多