uicollectionviewcontroller iphone ios uitableview header uicollectionview

iphone - uicollectionviewcontroller - Cómo agregar HeaderView en UICollectionView como TableViewView de UITableView



uicollectionviewcell indexpath (6)

¿Cómo puedo agregar una vista de encabezado / vista superior (no encabezado de sección) en la parte superior de UICollectionView ?

Debería actuar de forma UITableView como la propiedad tableHeaderView .

Por lo tanto, debe situarse en la parte superior de la vista de encabezado de la primera sección (antes de la sección en el índice 0), desplazarse junto con el resto del contenido y tener interacción con el usuario.

Lo mejor que he logrado hasta ahora es crear un XIB especial (con la subclase MyCollectionReusableView de UICollectionReusableView como propietario del archivo) para la primera vista de encabezado de sección que sea lo suficientemente grande como para contener también mis subvistas en el encabezado, es una especie de truco , Creo, y no he logrado detectar toques.

No estoy seguro si puedo hacer mi subclase MyCollectionReusableView para permitir toques o hay una mejor manera.


Creo que la mejor manera de hacerlo es subclase UICollectionViewLayout (UICollectionViewFlowLayout) y agregue los atributos de encabezado o pie de página necesarios.

Como todos los elementos, incluida la vista suplementaria en el diseño de UICollectionView de acuerdo con su propiedad collectionViewLayout , es el collectionviewlayout que decide si hay un encabezado (pie de página) o no.

Use contentInset es más fácil, pero puede haber un problema cuando desea ocultar o mostrar el encabezado dinámicamente.

He escrito un protocolo para lograr esto, que podría ser adoptado por cualquier subclase de UICollectionViewLayout para que tenga un encabezado o pie de página. Puedes encontrarlo here.

La idea principal es crear un UICollectionViewLayoutAttributes para el encabezado y devolverlo en layoutAttributesForElements(in rect: CGRect) si es necesario, tendrá que modificar todos los demás atributos, todas sus ubicaciones deben moverse hacia abajo por la altura del encabezado porque el encabezado es sobre todos ellos.


He puesto una vista en la parte superior de una vista de colección simplemente agregando un UIView como una subvista de la vista de colección. Se desplaza hacia arriba con la vista de colección y tiene una interacción normal con el usuario de UIView. Esto funciona bien si no tiene un encabezado de sección, pero no funciona si lo hace. En esa situación, no veo nada malo en la forma en que lo haces. No estoy seguro de por qué no estás detectando toques, funcionan bien para mí.


La mejor manera de lograr esto es hacer un encabezado de sección para la primera sección. Luego configure la propiedad de UICollectionViewFlowLayout:

@property(nonatomic) BOOL sectionHeadersPinToVisibleBounds

o rápido

var sectionHeadersPinToVisibleBounds: Bool

a NO (falso para rápido). Esto asegurará que el encabezado de la sección se desplaza de manera continua con las celdas y que no quede anclado en la parte superior como normalmente lo haría un encabezado de sección.


Terminé usando una extensión UICollectionView para agregar mi encabezado personalizado. Usando una etiqueta específica, puedo falsificar la propiedad almacenada para identificar mi encabezado personalizado (todo transparente desde el exterior). Es posible que tenga que desplazarse a un desplazamiento específico si el diseño de UICollectionView no se completa cuando agrega su encabezado personalizado.

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 se refiere al número de etiqueta que le das a tu encabezado. Asegúrese de que no sea la etiqueta de otra Vista incrustada en su UICollectionView.


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() } }


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];

Utilizo el atributo contentInset para insertar un marco en la parte superior de UICollectionView , luego le agrego la vista de imagen y se realiza correctamente. Creo que puede actuar de forma UITableView como la propiedad tableHeaderView . ¿Qué piensas?