2017-03-16 29 views
1

我有一个UICollectionViewSubclass使用自定义UICOllectionViewLayout如何正确处理UICollectionViewLayout的itemSize的方向变化

如何做最好的我处理方向上的变化改变itemSize?

class CollectSubclass: UICollectionView { 

    /// When orientation changes, then invalidate the layout 
    open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { 
     super.traitCollectionDidChange(previousTraitCollection) 

     if ((traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass) || (traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass)) { 
      collectionViewLayout.invalidateLayout() 
     } 
    } 
} 

一旦布局的方向变化无效, 我计算细胞的size.width,到UICollectionView的的width

这工作了iPhone 7加模拟器的很好,但未能就小了模拟器像iPhone 7,5,SE等

看来,一旦invalidateLayout被调用时,下面的函数被触发

/// Lays out subviews. 
override open func layoutSubviews() { 
    super.layoutSubviews() 
} 

该函数依次调用UICollectionViewLayout子类中的prepare函数,其中我使用collectionView的新帧来计​​算单元格的大小。

在iPhone-7-Plus上,traitCollectionDidChange被触发一次。一旦触发prepare一次,触发layoutSubviews

然而,在较小的模拟器上,traitCollectionDidChange被触发一次,但layoutSubviews被触发两次。

在第一次触发layoutSubviews时,UICO选择视图的帧大小为,几乎是它应该是什么。而在第二个触发器上,UICOllectionView的帧大小现在应该是正确的大小。

被两次调用两次不同的框架大小将导致我准备两次布局(这是非常昂贵的)。

有没有从UICOllectionViews和UICollectionViewLayouts子类中错过的东西?任何帮助表示赞赏。

我也可以在需要时

回答

1

如果在你的设置,你UICollectionViewCells之一的宽度仅基于UICollectionView的大小和屏幕的大小和方向(提供示例项目没有其他因素),以下是设置集合视图单元大小的一种简洁方法:

1)首次加载视图时,预先计算单元在纵向和横向上的大小。还要创建一个变量currCellDimensions来保存单元格的当前尺寸,并设置其初始值。

2)重写功能viewWillTransitionToSize沿着这些路线:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 
    setCurrentCollectionCellDimensions(size) // This code executes before the rotation begins, but "size" is the size that the main view is going to be after the rotation occurs. As of iOS 8, the size of an object swaps its width and its height when the UI changes its orientation. 
    } 

3)实施setCurrentCollectionCellDimensions():

func setCurrentCollectionCellDimensions(newSize: CGSize) { 

    if (newSize.width < newSize.height) { 
     // set currCellDimensions to what it should be in portrait orientation 
    } else { 
     // set currCellDimension to what it should be in landscape orientation 
    } 

    if collectionView != nil { 

     collectionView.collectionViewLayout.invalidateLayout() // To trigger sizeForItemAtIndexPath to recalculate cell sizes 

    collectionView.reloadData() // To trigger cellForItemAtIndexPath to redraw the cells that are visible to the user. Without this call, the cell layout looks wrong on some iPhones. 
    } 
} 

4)最后,具有sizeForItemAtIndexPath()返回currCellDimensions

+0

嗨,我无法使用'viewWillTransitionToSize'函数,因为我正在创建一个UICOllectionView子类,而不是UIViewCOntroller子类。我没有权限访问ViewController(仅作为collectionView的弱代理) –

+0

有没有什么方法可以在不使用视图控制器的情况下知道'viewWillTransitionToSize'? –

+0

不,但无论哪种视图控制器将实例化你的'UICollectionView'子类的实例,你都可以实现'viewWillTransitionToSize()'。然后在'viewWillTransitionToSize()'中,而不是调用'setCurrentCollectionCellDimensions(size)',调用'collectionView.setCurrentCollectionCellDimensions(size)'。你的一些逻辑必须来自视图控制器,其中一些将成为你的UICollectionView子类的一部分,但他们可以相互沟通。 – ClayJ