如何在UICollectionView
的顶部添加标题视图/顶部视图(不是章节标题)?
它应该完全符合UITableView
的{{1}}属性。
因此它需要位于第一部分标题视图的顶部(在索引0的部分之前),与其他内容一起滚动,并进行用户交互。
到目前为止,我提出的最好的方法是创建一个特殊的XIB(tableHeaderView
子类MyCollectionReusableView
作为文件的所有者),第一部分标题视图也足够大在标题中包含我的子视图,我认为这是一种黑客行为,我还没有设法检测到触摸。
不确定我是否可以让我的UICollectionReusableView
子类允许触摸或者有更好的方法。
答案 0 :(得分:54)
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 320, self.view.frame.size.height) collectionViewLayout:flowlayout];
self.collectionView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);
UIImageView *imagev = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"015.png"]];
imagev.frame = CGRectMake(0, -50, 320, 50);
[self.collectionView addSubview: imagev];
[self.view addSubview: _collectionView];
我使用属性contentInset
将一个框架插入UICollectionView
的顶部,然后我将图片视图添加到其中,然后成功。我认为它可以完全符合UITableView
的{{1}}属性。你觉得怎么样?
答案 1 :(得分:5)
我通过添加UIView作为集合视图的子视图,将视图放在集合视图的顶部。它确实向上滚动集合视图,它具有正常的UIView用户交互。如果您没有节标题,这可以正常工作,但如果您没有,则无效。在那种情况下,我认为你做这件事的方式没有任何问题。我不确定为什么你没有检测到触摸,它们对我来说很好。
答案 2 :(得分:4)
自 iOS 13 起,设置标头的规范方法是使用 UICollectionViewCompositionalLayoutConfiguration
这种方式允许为集合视图设置每个部分或全局的 boundarySupplementaryItems
。
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
let header = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize, elementKind: "header", alignment: .top)
let config = NSCollectionViewCompositionalLayoutConfiguration()
config.boundarySupplementaryItems = [header]
let layout = UICollectionViewCompositionalLayout(sectionProvider: sectionProvider, configuration: config)
return layout
要了解更多信息,请访问官方文档:https://developer.apple.com/documentation/appkit/nscollectionviewcompositionallayoutconfiguration
答案 3 :(得分:3)
实现此目的的最佳方法是为第一部分创建一个节头。然后设置UICollectionViewFlowLayout的属性:
@property(nonatomic) BOOL sectionHeadersPinToVisibleBounds
或swift
var sectionHeadersPinToVisibleBounds: Bool
到NO(对于swift是假的)。这将确保节标题与单元格连续滚动,并且不会像节标题通常那样固定到顶部。
答案 4 :(得分:1)
我最终使用UICollectionView扩展来添加我的自定义标头。使用特定标签,我能够伪造存储的属性以识别我的自定义标头(从外部透明)。 如果在添加自定义标头时未完成UICollectionView的布局,则可能必须滚动到特定偏移量。
extension UICollectionView {
var currentCustomHeaderView: UIView? {
return self.viewWithTag(CustomCollectionViewHeaderTag)
}
func asssignCustomHeaderView(headerView: UIView, sideMarginInsets: CGFloat = 0) {
guard self.viewWithTag(CustomCollectionViewHeaderTag) == nil else {
return
}
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
headerView.frame = CGRect(x: sideMarginInsets, y: -height + self.contentInset.top, width: self.frame.width - (2 * sideMarginInsets), height: height)
headerView.tag = CustomCollectionViewHeaderTag
self.addSubview(headerView)
self.contentInset = UIEdgeInsets(top: height, left: self.contentInset.left, bottom: self.contentInset.bottom, right: self.contentInset.right)
}
func removeCustomHeaderView() {
if let customHeaderView = self.viewWithTag(CustomCollectionViewHeaderTag) {
let headerHeight = customHeaderView.frame.height
customHeaderView.removeFromSuperview()
self.contentInset = UIEdgeInsets(top: self.contentInset.top - headerHeight, left: self.contentInset.left, bottom: self.contentInset.bottom, right: self.contentInset.right)
}
}
}
CustomCollectionViewHeaderTag是指您为标题指定的标记号。确保它不是UICollectionView中嵌入的anotherView的标记。
答案 5 :(得分:0)
我认为实现此目的的最佳方法是将UICollectionViewLayout(UICollectionViewFlowLayout)子类化并添加所需的页眉或页脚属性。
由于所有项目都包括UICollectionView布局中的补充视图根据其collectionViewLayout
属性,因此collectionviewlayout
决定是否存在页眉(页脚)。
使用contentInset
更容易,但是当您想要动态隐藏或显示标题时可能会出现问题。
我已经编写了一个协议来完成这个任务,UICollectionViewLayout的任何子类都可以使用它来使它有一个页眉或页脚。你可以找到它here.
主要想法是为标题创建UICollectionViewLayoutAttributes
并在layoutAttributesForElements(in rect: CGRect)
中将其返回,如果需要,您必须修改所有其他属性,所有位置都应按标题向下移动高度,因为标题在它们之上。
答案 6 :(得分:-2)
private var PreviousInsetKey: Void?
extension UIView {
var previousInset:CGFloat {
get {
return objc_getAssociatedObject(self, &PreviousInsetKey) as? CGFloat ?? 0.0
}
set {
if newValue == -1{
objc_setAssociatedObject(self, &PreviousInsetKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
else{
objc_setAssociatedObject(self, &PreviousInsetKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
func addOnCollectionView(cv: UICollectionView){
if self.superview == nil{
var frame = self.frame
frame.size.width = SCREEN_WIDTH
cv.frame = frame
self.addOnView(view: cv)
let flow = cv.collectionViewLayout as! UICollectionViewFlowLayout
var inset = flow.sectionInset
previousInset = inset.top
inset.top = frame.size.height
flow.sectionInset = inset
}
}
func removeFromCollectionView(cv: UICollectionView){
if self.superview == nil{
return
}
self.removeFromSuperview()
let flow = cv.collectionViewLayout as! UICollectionViewFlowLayout
var inset = flow.sectionInset
inset.top = previousInset
flow.sectionInset = inset
previousInset = -1
}
func addOnView(view: UIView){
view.addSubview(self)
self.translatesAutoresizingMaskIntoConstraints = false
let leftConstraint = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0)
let widthConstraint = NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: view.frame.size.width)
let heightConstraint = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: view.frame.size.height)
let topConstraint = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 0)
view.addConstraints([leftConstraint, widthConstraint, heightConstraint, topConstraint])
self.layoutIfNeeded()
view.layoutIfNeeded()
}
}