Swift 5 个 UICollectionViewCell 自动布局约束
Swift 5 UICollectionViewCell Autolayout constraints
久违了 Swift 和 UIKit 的重制
工作流程:
- 我创建了一个 ViewController,其中
UICollectionView
将其中心在 X 轴和 Y 轴上对齐,并且宽度和高度与根视图成比例。
- 分配给collectionview.delegate和collectionView.dataSource它适当的class实例对应
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
- 我创建了一个 UICollectionViewCell 并在 cellforItemAt 中调用了 dequeuereusablecell...
- 我可以访问 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 )
- 在 ViewController 中实施
traitCollectionDidChange
并在 collectionView 上强制重新加载数据
- 我已经用很多设备(确切地说是模拟器)进行了测试,它适用于大多数情况
场景:
- 如果水平和垂直大小 class 完全相同 - 示例:
iPad Mini
- ItemCount 为 1
- 页面首先以横向打开
- 然后页面旋转成纵向
问题:
- 集合不会重新加载,因为 traitcollection 没有改变。
- Cell的当前宽度大于CollectionView的当前宽度
我尝试的几种方法:
- 在 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)
}
- 与第一种方法类似,但尝试在 interfacebuilder 中应用约束。没有办法做到这一点,因为在 CollectionView 和 CollectionViewCell 之间单击和拖动命令根本不会提示任何约束
问题:
- 我是否应该实现方向更改侦听器之类的东西并在那里重新加载 collectionView 而不是特征收集更改侦听器?
- 如果我选择 orientation Listener,如果我将来致力于多任务支持,如果我在不更改 Orientation 的情况下更改 traitCollection,则此方法无效。
- 如果我同时实现 traitCollection 和 Orientation Change Listeners,很多时候它们会发生冲突,并且会尝试重新加载 collectionView 两次。
- 有人可以帮我找到适合这个问题的解决方案吗?
根据 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.
久违了 Swift 和 UIKit 的重制
工作流程:
- 我创建了一个 ViewController,其中
UICollectionView
将其中心在 X 轴和 Y 轴上对齐,并且宽度和高度与根视图成比例。 - 分配给collectionview.delegate和collectionView.dataSource它适当的class实例对应
UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
- 我创建了一个 UICollectionViewCell 并在 cellforItemAt 中调用了 dequeuereusablecell...
- 我可以访问 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 )
- 在 ViewController 中实施
traitCollectionDidChange
并在 collectionView 上强制重新加载数据
- 我已经用很多设备(确切地说是模拟器)进行了测试,它适用于大多数情况
场景:
- 如果水平和垂直大小 class 完全相同 - 示例:
iPad Mini
- ItemCount 为 1
- 页面首先以横向打开
- 然后页面旋转成纵向
问题:
- 集合不会重新加载,因为 traitcollection 没有改变。
- Cell的当前宽度大于CollectionView的当前宽度
我尝试的几种方法:
- 在 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) }
- 与第一种方法类似,但尝试在 interfacebuilder 中应用约束。没有办法做到这一点,因为在 CollectionView 和 CollectionViewCell 之间单击和拖动命令根本不会提示任何约束
问题:
- 我是否应该实现方向更改侦听器之类的东西并在那里重新加载 collectionView 而不是特征收集更改侦听器?
- 如果我选择 orientation Listener,如果我将来致力于多任务支持,如果我在不更改 Orientation 的情况下更改 traitCollection,则此方法无效。
- 如果我同时实现 traitCollection 和 Orientation Change Listeners,很多时候它们会发生冲突,并且会尝试重新加载 collectionView 两次。
- 有人可以帮我找到适合这个问题的解决方案吗?
根据 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.