如何创建自动调整标签内容 + 字体大小更改的 UICollectionView 部分 Header?
How to create UICollectionView section Header which autosizes to label content + font size change?
我想在 UICollectionView
中添加一个 header 部分,其中包含两个标签以显示标题和信息描述。两个标签都可以显示多行文本,header 大小应该自动适应标签内容。
TL;DR
当标签字体更改 appearance()
代理时,自动布局似乎失败。有解决办法吗?
完整描述
这是我在 IB 中设置 header 视图的方式:
可以看出,IB 报告了一个问题。这是一个 “内容优先级歧义”,可以通过将 InfoLabel 的垂直内容拥抱优先级设置为 250 轻松解决。
header 视图添加到 ViewController 中,referenceSizeForHeaderInSection
用于设置大小:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath) as? SectionHeaderView ?? SectionHeaderView()
headerView.titleLabel.text = "Title Label with long text. More text..."
headerView.infoLabel.text = "Info Label with long text. More text...."
return headerView
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
// Get the view for the first header
let indexPath = IndexPath(row: 0, section: section)
let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: indexPath)
// Use this view to calculate the optimal size based on the collection view's width
return headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
}
到目前为止一切看起来都很好。但是,当使用 appearance()
代理更改标签字体时,它失败了:
// called in application:didFinishLaunchingWithOptions
UILabel.appearance(whenContainedInInstancesOf: [SectionHeaderView.self]).font = UIFont.systemFont(ofSize: 10)
左边的截图是不改变字体大小的布局,右边的截图是使用UILabel.appearance
:
后的布局
字体大小似乎在 计算 header 大小后更新,现在 re-calculation 被触发。
如何解决?
如果两个标签具有相同的拥抱优先级(IB中的错误被简单地忽略),问题几乎是一样的。但是,如果没有明确的信息,自动布局会简单地决定拉伸标题标签而不是信息标签。
这是一种方法:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
// Get the view for the first header
let indexPath = IndexPath(row: 0, section: section)
let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: indexPath) as! SectionHeaderView
// appearance is not applied until view is added to the view hierarchy, so
// get the UIAppearance protocol for UILabel contained in SectionHeaderView class
let a = UILabel.appearance(whenContainedInInstancesOf: [SectionHeaderView.self])
// update the label(s) font property to the appearance font
headerView.titleLabel.font = a.font
headerView.infoLabel.font = a.font
// Use this view to calculate the optimal size based on the collection view's width
return headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
}
我想在 UICollectionView
中添加一个 header 部分,其中包含两个标签以显示标题和信息描述。两个标签都可以显示多行文本,header 大小应该自动适应标签内容。
TL;DR
当标签字体更改 appearance()
代理时,自动布局似乎失败。有解决办法吗?
完整描述
这是我在 IB 中设置 header 视图的方式:
可以看出,IB 报告了一个问题。这是一个 “内容优先级歧义”,可以通过将 InfoLabel 的垂直内容拥抱优先级设置为 250 轻松解决。
header 视图添加到 ViewController 中,referenceSizeForHeaderInSection
用于设置大小:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "header", for: indexPath) as? SectionHeaderView ?? SectionHeaderView()
headerView.titleLabel.text = "Title Label with long text. More text..."
headerView.infoLabel.text = "Info Label with long text. More text...."
return headerView
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
// Get the view for the first header
let indexPath = IndexPath(row: 0, section: section)
let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: indexPath)
// Use this view to calculate the optimal size based on the collection view's width
return headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
}
到目前为止一切看起来都很好。但是,当使用 appearance()
代理更改标签字体时,它失败了:
// called in application:didFinishLaunchingWithOptions
UILabel.appearance(whenContainedInInstancesOf: [SectionHeaderView.self]).font = UIFont.systemFont(ofSize: 10)
左边的截图是不改变字体大小的布局,右边的截图是使用UILabel.appearance
:
字体大小似乎在 计算 header 大小后更新,现在 re-calculation 被触发。
如何解决?
如果两个标签具有相同的拥抱优先级(IB中的错误被简单地忽略),问题几乎是一样的。但是,如果没有明确的信息,自动布局会简单地决定拉伸标题标签而不是信息标签。
这是一种方法:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
// Get the view for the first header
let indexPath = IndexPath(row: 0, section: section)
let headerView = self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: indexPath) as! SectionHeaderView
// appearance is not applied until view is added to the view hierarchy, so
// get the UIAppearance protocol for UILabel contained in SectionHeaderView class
let a = UILabel.appearance(whenContainedInInstancesOf: [SectionHeaderView.self])
// update the label(s) font property to the appearance font
headerView.titleLabel.font = a.font
headerView.infoLabel.font = a.font
// Use this view to calculate the optimal size based on the collection view's width
return headerView.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
}