Swift 5 个 UICollectionViewCell 自动布局约束

Swift 5 UICollectionViewCell Autolayout constraints

久违了 Swift 和 UIKit 的重制

工作流程:

  1. 我创建了一个 ViewController,其中 UICollectionView 将其中心在 X 轴和 Y 轴上对齐,并且宽度和高度与根视图成比例。
  2. 分配给collectionview.delegate和collectionView.dataSource它适当的class实例对应UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
  3. 我创建了一个 UICollectionViewCell 并在 cellforItemAt 中调用了 dequeuereusablecell...
  4. 我可以访问 sizeForItemAt... 来计算合适的尺寸
    // item count represents number of cells per row in a section within collectionview
    let refWidth = collectionView.frame.width / CGFloat(itemCount); // sectionInsets are UIEdgeInsets.zero for simplicity in reproducing the issue
    let calculatedSize = CGSize(width: refWidth, height: refWidth/2 )
    
  5. 在 ViewController 中实施 traitCollectionDidChange 并在 collectionView
  6. 上强制重新加载数据
  7. 我已经用很多设备(确切地说是模拟器)进行了测试,它适用于大多数情况

场景:

  1. 如果水平和垂直大小 class 完全相同 - 示例:iPad Mini
  2. ItemCount 为 1
  3. 页面首先以横向打开
  4. 然后页面旋转成纵向

问题:

  1. 集合不会重新加载,因为 traitcollection 没有改变。
  2. Cell的当前宽度大于CollectionView的当前宽度

我尝试的几种方法:

  1. 在 cellForItemAt... 方法中,在返回单元格之前,我已经使用 CollectionView 向单元格添加了一个约束,如下所示 - `Applicatin Crashed 并显示一条无法应用此类约束的消息。
        let itemCount = itemsPerRowInEachSection(collectionView)
        if cell.contentView.constraints.first(where: { cst in cst.identifier == "widthConst" }) != nil {
            let newConst = NSLayoutConstraint(item: cell,
                                              attribute: .width,
                                              relatedBy: .equal,
                                              toItem: collectionView,
                                              attribute: .width,
                                              multiplier: CGFloat(1)/CGFloat(itemCount),
                                              constant: 0)
            newConst.identifier = "widthConst"
            cell.addConstraint(newConst)
        }
    
  2. 与第一种方法类似,但尝试在 interfacebuilder 中应用约束。没有办法做到这一点,因为在 CollectionView 和 CollectionViewCell 之间单击和拖动命令根本不会提示任何约束

问题:

  1. 我是否应该实现方向更改侦听器之类的东西并在那里重新加载 collectionView 而不是特征收集更改侦听器?
    • 如果我选择 orientation Listener,如果我将来致力于多任务支持,如果我在不更改 Orientation 的情况下更改 traitCollection,则此方法无效。
    • 如果我同时实现 traitCollection 和 Orientation Change Listeners,很多时候它们会发生冲突,并且会尝试重新加载 collectionView 两次。
  2. 有人可以帮我找到适合这个问题的解决方案吗?

根据 OP 评论...

如果您需要根据视图的 大小 修改布局 - 例如在设备旋转时 - 您可以使用:

func viewWillTransition(to size: CGSize, 
               with coordinator: UIViewControllerTransitionCoordinator)

来自苹果的docs

UIKit calls this method before changing the size of a presented view controller’s view. You can override this method in your own objects and use it to perform additional tasks related to the size change. For example, a container view controller might use this method to override the traits of its embedded child view controllers. Use the provided coordinator object to animate any changes you make.