滚动旋转时 UICollectionView 崩溃(索引路径处补充项目的布局属性已更改而未失效..)

Posted

技术标签:

【中文标题】滚动旋转时 UICollectionView 崩溃(索引路径处补充项目的布局属性已更改而未失效..)【英文标题】:UICollectionView crashing when scrolling whist rotating (layout attributes for supplementary item at index path changed without invalidating..) 【发布时间】:2015-10-29 21:40:48 【问题描述】:

任何想法如何解决我的 UICollectionView 在滚动时旋转时崩溃的事实?

我分别使用以下方法进行滚动和旋转,并且每种方法似乎都可以正常工作。我刚刚注意到同时做这两件事时我会崩溃。因此,当我旋转设备并且在 prepareLayout 中计算新的布局属性时,这似乎与以下事实有关,即持续滚动正在触发“invalidateLayoutWithContext(invalidContext)”(见下文)。

想法?有没有办法在轮换期间暂停任何滚动响应(或忽略它们)?

轮换法 在视图控制器的 viewWillLayoutSubviews 中,我使整个布局无效

self.cal.collectionViewLayout.invalidateLayout()

滚动方式 为了让我有一个“粘性”装饰视图(标题),我不会使整个布局无效,因为它会降低性能,但请执行以下操作。在布局类中我覆盖 shouldInvalidateLayoutForBoundsChange

    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool 
        let invalidContext : UICollectionViewLayoutInvalidationContext = self.invalidationContextForBoundsChange(newBounds)

        // Keep Header Sticky
invalidContext.invalidateDecorationElementsOfKind(GCCalendarLayoutKind_Decorative1, atIndexPaths: [headerDecorativeIndexPath])

        // Apply Invalidation
        self.invalidateLayoutWithContext(invalidContext)        

        // Return normal super return (just in case of future ios upgrades)
        return super.shouldInvalidateLayoutForBoundsChange(newBounds)
    

注意这里我使装饰视图(标题)无效,而崩溃的错误是关于我的补充视图布局不同。

错误

2015-10-30 07:14:30.181 test3_collectionview[17086:3102132] * -[UICollectionViewData validateLayoutInRect:] 中的断言失败, /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.29.5/UICollectionViewData.m:408 2015-10-30 07:14:30.185 test3_collectionview[17086:3102132] * 由于未捕获的异常而终止应用程序 'NSInternalInconsistencyException',原因:'布局属性 索引路径上的补充项(length = 2, path = 0 - 0) 从 指数 路径:(长度 = 2,路径 = 0 - 0);元素 种类:(装饰1);帧 = (0 1085.5; 320 16); zIndex = 1;到 指数 路径:(长度 = 2,路径 = 0 - 0);元素 种类:(装饰1);帧 = (0 853.5; 320 16); zIndex = 1;没有 使布局无效' *** 首先抛出调用栈:

【问题讨论】:

如果不覆盖shouldInvalidateLayoutForBoundsChange方法,崩溃还会继续发生吗? @Lefteris 在这种情况下不会发生崩溃,但是我不确定如何在不影响 collectionView 性能的情况下实现我的目标(即不确定如何使用 invalidateLayoutWithContext 方法) 【参考方案1】:

我不确定这是否足够,但我会按照这些思路尝试一下(集合视图是滚动视图):

import CoreGraphics

class myController: UIViewController, UIScrollViewDelegate 

    var myScrollView = UIScrollView()

    override func viewDidLoad() 
        self.view.addSubview(myScrollView)
    

    // This will capture rotation events
    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) 
        self.myScrollView.scrollEnabled = false
        coordinator.notifyWhenInteractionEndsUsingBlock( _ in self.myScrollView.scrollEnabled = true )
        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    

    func scrollViewDidScroll(scrollView: UIScrollView) 
        // This will not ignore scroll but perhaps can help keeping things "tidy" and "performant" during rotation.  Not sure
        if myScrollView.scrollEnabled == false 
            let offset = scrollView.contentOffset
            myScrollView.setContentOffset(offset, animated: false)
        
       

【讨论】:

不确定这将如何解决我的问题? “invalidateLayoutWithContext”在哪里适合... 如果我(昨天)有评论的权限,我会更恰当地发表评论。当您不覆盖“shouldInvalidateLayoutForBoundsChange”时,您似乎没有崩溃。我的天真想法是,嗯,真的很天真:当发生旋转事件时,冻结滚动并阻止用户交互(以保持“干净”),同时设置 scrollEnabled = false。当滚动被禁用时,您可以“暂停”“shouldInvalidateLayoutForBoundsChange”(即使用默认行为)。也许我在这里遗漏了一些重要的东西。

以上是关于滚动旋转时 UICollectionView 崩溃(索引路径处补充项目的布局属性已更改而未失效..)的主要内容,如果未能解决你的问题,请参考以下文章

滚动到最后一项时 UICollectionView 崩溃

滚动 UICollectionView 使用大量内存导致崩溃

由于索引超出范围,uitableviewcell 滚动中的 uicollectionview 将崩溃

UICollectionViewFlowLayout 子类在滚动和重新加载时崩溃访问超出范围的数组

设备旋转后的 UICollectionView contentOffset

应用程序在“layoutAttributesForSupplementaryElement”上崩溃