Как добавить HeaderView в UICollectionView, например UITableView tableHeaderView
Как добавить заголовок/верхний вид (не заголовок раздела) в верхней части UICollectionView
?
Он должен действовать как свойство UITableView
tableHeaderView
.
Поэтому он должен сидеть поверх первого заголовка раздела (перед секцией с индексом 0), прокручивать вместе с остальной частью содержимого и взаимодействовать с пользователем.
Лучшее, что я до сих пор придумал, - создать специальный XIB (с подклассом MyCollectionReusableView
UICollectionReusableView
в качестве владельца файла) для первого заголовка заголовка, который достаточно велик, чтобы также содержать мои подпрограммы в заголовок, это вроде хак, я думаю, и мне не удалось обнаружить прикосновения.
Не уверен, могу ли я сделать мой подкласс MyCollectionReusableView
, чтобы разрешить касания или там лучший способ.
Ответы
Ответ 1
Я поставил представление в верхней части коллекции, просто добавив UIView в качестве подзадача представления коллекции. Он просматривает просмотр коллекции и имеет обычное пользовательское взаимодействие UIView. Это работает нормально, если у вас нет заголовка раздела, но он не работает, если вы это сделаете. В этой ситуации я не вижу ничего плохого в том, как вы это делаете. Я не уверен, почему вы не обнаруживаете прикосновений, они отлично работают для меня.
Ответ 2
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
tableHeaderView
. Как вы думаете?
Ответ 3
Лучший способ добиться этого - сделать заголовок раздела для первого раздела. Затем установите свойство UICollectionViewFlowLayout:
@property(nonatomic) BOOL sectionHeadersPinToVisibleBounds
или быстро
var sectionHeadersPinToVisibleBounds: Bool
до NO (false для быстрого). Это гарантирует, что заголовок секции непрерывно прокручивается с ячейками и не привязывается к вершине, как обычно, заголовок секции.
Ответ 4
Я думаю, что лучший способ выполнить это для подкласса UICollectionViewLayout (UICollectionViewFlowLayout) и добавить необходимые атрибуты верхнего или нижнего колонтитула.
Поскольку все элементы, включая дополнительный вид в макете UICollectionView, в соответствии с его свойством collectionViewLayout
, это collectionViewLayout
, который определяет, есть ли заголовок (нижний колонтитул) или нет.
Использовать contentInset
проще, но может возникнуть проблема, когда вы хотите скрыть или показать заголовок динамически.
Я написал протокол для этого, который может быть принят любым подклассом UICollectionViewLayout, чтобы он имел верхний или нижний колонтитул. Вы можете найти здесь.
Основная идея состоит в том, чтобы создать UICollectionViewLayoutAttributes
для заголовка и вернуть его в layoutAttributesForElements(in rect: CGRect)
, если потребуется, вам придется изменить все остальные атрибуты, все их местоположения должны быть перемещены вниз по высоте заголовка, потому что заголовок выше всех.
Ответ 5
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()
}
}