ios - tutorial - Vista UICollection y Vista suplementaria(encabezado)
uicollectionview programmatically swift (10)
Esta respuesta es similar a las otras en las que crea un método que verifica la fuente de datos, pero es un poco más simple. Parece que el problema está relacionado con el diseño de la vista de colección que se mantiene después de que la colección se ha publicado. Así que puse a cero las propiedades del diseño como se muestra a continuación y el error desapareció.
deinit {
let layout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.estimatedItemSize = CGSizeZero
layout.sectionInset = UIEdgeInsetsZero
layout.headerReferenceSize = CGSizeZero
}
Intento agregar una vista complementaria en mi UICollectionView
como encabezado. Estoy teniendo problemas para que funcione.
Utilizo un UICollectionViewFlowLayout
personalizado para devolver un contentSize
que siempre es al menos 1 píxel más grande que el marco (estoy usando un UIFreshControl
que solo funcionará si el UICollectionView
desplaza, y la configuración de collectionView.contentSize
no hace nada) y para invalidateLayout
el sectionInsert
en la sectionInsert
de sectionInsert
y itemSize
cambios:
-(void)setSectionInset:(UIEdgeInsets)sectionInset {
if (UIEdgeInsetsEqualToEdgeInsets(super.sectionInset, sectionInset)) {
return;
}
super.sectionInset = sectionInset;
[self invalidateLayout];
}
-(void) setItemSize:(CGSize)itemSize {
if (CGSizeEqualToSize(super.itemSize, itemSize)) {
return;
}
super.itemSize = itemSize;
[self invalidateLayout];
}
- (CGSize)collectionViewContentSize
{
CGFloat height = [super collectionViewContentSize].height;
// Always returns a contentSize larger then frame so it can scroll and UIRefreshControl will work
if (height < self.collectionView.bounds.size.height) {
height = self.collectionView.bounds.size.height + 1;
}
return CGSizeMake([super collectionViewContentSize].width, height);
}
UICollectionReusableView
una clase UICollectionReusableView
que es solo una UIView
con un UILabel
:
@implementation CollectionHeaderView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"CollectionHeaderView" owner:self options:nil];
if ([arrayOfViews count] < 1) {
return nil;
}
if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
return nil;
}
self = [arrayOfViews objectAtIndex:0];
self.headerLabel.text = @"This is a header. There are many like it.";
self.backgroundColor = [UIColor yellowColor];
}
return self;
}
Tratando de implementarlo:
DatasetLayout *collectionViewFlowLayout = [[DatasetLayout alloc] init];
collectionViewFlowLayout.itemSize = CGSizeMake(360, 160);
collectionViewFlowLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16);
collectionViewFlowLayout.minimumInteritemSpacing = 16;
collectionViewFlowLayout.minimumLineSpacing = 16;
collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
collectionView.backgroundColor = [UIColor yellowColor];
collectionView.delegate = self;
collectionView.dataSource = self;
Registro la clase
[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
e implementar el delegado:
-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
CollectionHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView" forIndexPath:indexPath];
headerView.headerLabel.text = @"Blarg!";
return headerView;
}
La línea
collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100);
causa el error:
*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:1150
*** Terminating app due to uncaught exception ''NSInternalInconsistencyException'', reason: ''UICollectionView dataSource is not set''
Si lo comento, se ejecuta pero sin encabezado.
¿Qué estoy haciendo mal o no estoy implementando?
Las respuestas en este tema son bastante antiguas y no funcionan en iOS8 y iOS9. Si aún tiene el problema descrito, consulte el siguiente tema: UICollectionView y Supplementary View crash
EDITAR :
Aquí está la respuesta, en caso de que el enlace no sea válido:
Si está utilizando un diseño personalizado en su vista de colección, verifique si su fuente de datos es nula en:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
El resultado debe verse algo como esto:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
if (self.collectionView.dataSource != nil) {
// Your layout code
return array;
}
return nil;
}
Este cambio resuelve el siguiente problema:
- Error de aserción en - [UICollectionView _createPreparedSupplementaryViewForElementOfKind: atIndexPath: withLayoutAttributes: applyAttributes:]
También puede consultar el siguiente tema, sin embargo, no resolvió nada en mi caso:
Eliminación de espacios vacíos, si el encabezado de la sección está oculto en UICollectionView
Espero que te ayude, y no pierdas tanto tiempo como yo.
Limpié mi código y eliminé el UICollectionView que había creado en IB y lo creé todo en código. Lo ejecuté nuevamente y obtuve un error diferente y me di cuenta de que no configuré el delegado o dataSource en IB. Yo si:
self.collectionView.delegate = self;
self.collectionView.datasource = self;
Pero eso no debe haber sido lo suficientemente bueno.
Entonces, con UICollectionView creado en IB y no configurando el delgate / datasource en IB, sino en el código:
[self.view bringSubviewToFront:self.collectionView];
self.collectionView.collectionViewLayout = collectionViewFlowLayout;
self.collectionView.backgroundColor = [UIColor orangeColor];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
[self.collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];
[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
fue un problema Lo redibuje para crear el UICollectionView todo en código:
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewFlowLayout];
collectionView.translatesAutoresizingMaskIntoConstraints = FALSE;
collectionView.backgroundColor = [UIColor yellowColor];
collectionView.delegate = self;
collectionView.dataSource = self;
[collectionView registerClass:[DatasetCell class] forCellWithReuseIdentifier:@"cvCell"];
[collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
[self.view addSubview:collectionView];
self.collectionView = collectionView;
y me sale un error diferente:
*** Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2380.17/UICollectionView.m:2249
*** Terminating app due to uncaught exception ''NSInternalInconsistencyException'', reason: ''could not dequeue a view of kind: UICollectionElementKindSectionHeader with identifier CollectionHeaderView - must register a nib or a class for the identifier or connect a prototype cell in a storyboard''
que voy a tratar de averiguar.
EDITAR:
Lo descubrí, estaba registrando el encabezado incorrectamente:
[collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
cambiado a:
UINib *headerNib = [UINib nibWithNibName:@"CollectionHeaderView" bundle:nil];
[collectionView registerNib:headerNib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"];
y todo funciona. Sin embargo, no estoy seguro de cómo funcionó el registerClass:
Me enfrenté con un problema similar, pero mi aplicación se bloqueó después de que abrí mi UICollectionViewController mediante programación. Por alguna razón (creo que es solo un error en el SDK) self.collectionView estaba vivo después de que su controlador se destruyera, lo que causó este error:
*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-2935.137/UICollectionView.m:1305
*** Terminating app due to uncaught exception ''NSInternalInconsistencyException'', reason: ''UICollectionView dataSource is not set''
La solución es simplemente anular -dealloc en UICollectionViewController y lanzar self.collectionView manualmente. Código ARC:
- (void)dealloc {
self.collectionView = nil;
}
Espero que esto ahorre tiempo para alguien.
Prueba esto :
self.collectionView?.dataSource = nil
self.collectionView = nil
Funcionó para mí;)
Seguí recibiendo el mismo error. Había configurado el CustomHeaderView para mi collectionView. Tenía clase de la Vista reutilizable de la colección en mi CustomHeaderView y había establecido el identificador. I 1/2 hora tratando de averiguar por qué esto estaba fallando.
La aplicación de finalización debido a la excepción no detectada ''NSInternalInconsistencyException'', razón: ''no se pudo poner en cola una vista de tipo: UICollectionElementKindSectionFooter con identificador SectionHeader: debe registrar una punta o una clase para el identificador o conectar un prototipo de celda en un guión gráfico''
Necesitas leer los registros cuidadosamente ... lección aprendida.
''no se ha podido poner en cola una vista de tipo: UICollectionElementKindSectionFooter
La razón se debe a que en el guión gráfico, en el collectionView Identity Inspector, había revisado los dos Accesorios: Encabezado de sección y Pie de sección. Solo necesitaba el encabezado de la sección. Simplemente desmarca el pie de página ... construye y corre ... ¡PASEO!
Si observa el mensaje de error, indica que la fuente de datos no está establecida. Esto debería arreglarlo:
self.collectionView.dataSource = self;
Asegúrese de que su controlador de vista implementa el protocolo de origen de datos:
YourViewController : UIViewController<UICollectionViewDataSource>
También tengo este error molesto:
*** Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:], /SourceCache/UIKit/UIKit-3347.44/UICollectionView.m:1400
*** Terminating app due to uncaught exception ''NSInternalInconsistencyException'', reason: ''UICollectionView dataSource is not set''
Y encontré algunas personas resolviendo este error haciendo
- (void)dealloc {
self.collectionView = nil;
}
o en veloz
deinit {
collectionView = nil
}
Sin embargo, ninguno de estos resolvió mi caída. Probé algunas cosas y el siguiente "truco" resolvió este molesto error:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if collectionView.dataSource != nil {
return someHeaderSize
} else {
return CGSizeZero
}
}
Tenía el mismo problema y, de manera similar, no estaba registrando correctamente el encabezado. hay varios hilos aquí que todos sugieren el uso de un Nib para definir el encabezado, pero lo he hecho de manera diferente y está funcionando bien.
Tengo un encabezado personalizado SizeCollectionHeader, que hereda el UICollectionReusableView. Se registra así.
[self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"UICollectionElementKindSectionHeader"
withReuseIdentifier:@"SupplementaryViewIdentifier"];
y está funcionando bien.
Mi problema inicial fue que tenía un valor "tipo" aleatorio como este.
[self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"SupplementaryViewKind"
withReuseIdentifier:@"SupplementaryViewIdentifier"];
Esto se estrellará.
Así que solo quería comentar a cualquier persona que esté buscando aquí que no necesita usar una punta.
Un error de iOS9, en viewloctroller dealloc set layer delegate nil.
- (void)dealloc{
if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"9"]) {
self.collectionView.layer.delegate = nil;
}
}