2013-03-05 11 views
15

Provare ad aggiungere una vista supplementare al mio UICollectionView come intestazione. Sto avendo problemi per farlo funzionare.UICollectionView e visualizzazione supplementare (intestazione)

Io uso una consuetudine UICollectionViewFlowLayout per restituire un contentSize che è sempre almeno 1 pixel più grande allora il telaio (sto usando un UIFreshControl che funziona solo se le UICollectionView pergamene e impostare collectionView.contentSize non fa direttamente nulla) ea invalidateLayout su sectionInsert e itemSize modifiche:

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

ho creato una classe UICollectionReusableView che è solo un 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; 
} 

Cercando per la sua attuazione:

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; 

mi registro di classe:

[self.collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"]; 

e attuare il delegato:

-(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 linea

collectionViewFlowLayout.headerReferenceSize = CGSizeMake(0, 100); 

causa l'errore:

Se commento fuori, corre ma nessuna intestazione.

Cosa sto facendo male o non sto implementando?

+0

L'errore si sta lamentando del fatto che "UICollectionView dataSource non è impostato". ** - collectionView: viewForSupplementaryElementOfKind: atIndexPath: ** è, in effetti, un metodo di protocollo dell'origine dati non un metodo di protocollo delegato. Hai la proprietà ** dataSource ** del set di viste dell'insieme? –

+0

Non sono esattamente sicuro di cosa intendi con "la proprietà dataSource dell'insieme di viste dell'insieme?"? Ho un dataSource e viene visualizzato se non tento di fare un'intestazione. – Padin215

+0

L'oggetto UICollectionView ha una proprietà dataSource.L'errore che stai ricevendo sta dicendo che non lo hai impostato sull'oggetto che implementerà lo - collectionView: viewForSupplementaryElementOfKind: atIndexPath: metodo –

risposta

1

Se si guarda il messaggio di errore, si dice che l'origine dati non è impostata. Questo dovrebbe risolvere il problema:

self.collectionView.dataSource = self;

Assicurarsi che il controller della vista implementa il protocollo di origine di dati:

YourViewController : UIViewController<UICollectionViewDataSource>

+0

Ho aggiunto la mia implementazione UICollectionView che imposto personalmente sull'origine dati. – Padin215

+0

Ho incluso il delegato, penso di aver capito il problema – Padin215

6

ho ripulito il mio codice e rimosso l'UICollectionView che avevo creato in IB e ha creato tutto in codice. L'ho eseguito di nuovo e ho ottenuto un errore diverso e mi sono reso conto che non ho impostato il delegato o dataSource in IB. Ho fatto:

self.collectionView.delegate = self; 
self.collectionView.datasource = self; 

Ma questo non deve essere stato abbastanza buono.

Quindi, con UICollectionView creato in IB e non l'impostazione del delgate/origine dati in IB, ma piuttosto nel codice:

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

era un problema.Ho rifatto per creare l'UICollectionView tutto in codice:

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; 

e ottengo un errore diverso:

*** 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' 

che cercherò di capire.

EDIT:

capito, stavo registrando l'intestazione in modo non corretto:

[collectionView registerClass:[CollectionHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"]; 

passati a:

UINib *headerNib = [UINib nibWithNibName:@"CollectionHeaderView" bundle:nil]; 

[collectionView registerNib:headerNib forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionHeaderView"]; 

e tutto funziona. Non sono del tutto sicuro di come lo registerClass: non abbia funzionato.

13

Ho dovuto affrontare il problema simile, ma la mia app si è bloccata dopo che ho programmato il mio UICollectionViewController. In qualche motivo (credo che sia solo un bug nel SDK) self.collectionView era vivo dopo la sua controllore distruggere, causando in tal modo questo fallimento:

*** 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 soluzione è a sovrascrivono -dealloc in UICollectionViewController e rilasciare self.collectionView manualmente. Codice ARC:

- (void)dealloc { 

    self.collectionView = nil; 
} 

Spero che questo risparmi tempo per qualcuno.

+0

Ran nello stesso problema. Sicuramente sembra un bug nell'SDK. Sta succedendo solo su iOS 8 per me. – Jason

+0

Bingo. Grazie!! – cleverbit

+0

Ottenuto con un iPhone 7.1.2 4. –

0

Ho anche ottenuto questo errore fastidioso:

*** 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' 

e ho trovato alcune persone che risolvono questo errore facendo

- (void)dealloc { 
    self.collectionView = nil; 
} 

o in rapida:

deinit { 
    collectionView = nil 
} 

tuttavia nessuno di questi risolto il mio incidente. Ho provato un paio di cose e la seguente "hack" risolto questo fastidioso bug:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { 
    if collectionView.dataSource != nil { 
     return someHeaderSize 
    } else { 
     return CGSizeZero 
    } 
} 
0

ho avuto lo stesso problema e allo stesso modo, non stavo registrando l'intestazione in modo corretto. ci sono diversi thread qui che suggeriscono tutti di usare un pennino per definire l'intestazione, ma l'ho fatto diversamente e sta funzionando bene.

Ho un'intestazione personalizzata SizeCollectionHeader, che eredita UICollectionReusableView. È registrato come questo.

[self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"UICollectionElementKindSectionHeader" 
                      withReuseIdentifier:@"SupplementaryViewIdentifier"]; 

e funziona correttamente.

il mio problema iniziale era che aveva un valore "Kind" casuale come questo.

[self.collectionView registerClass:[GRSizeCollectionHeader class] forSupplementaryViewOfKind:@"SupplementaryViewKind" 
                      withReuseIdentifier:@"SupplementaryViewIdentifier"]; 

Questo si bloccherà.

Quindi volevo solo commentare per chiunque stia guardando qui che non è necessario utilizzare un pennino.

10

Le risposte in questo argomento sono piuttosto vecchie e non funzionano in iOS8 e iOS9. Se si continua ad avere il problema descritto, controllare il seguente argomento: UICollectionView and Supplementary View crash

EDIT:

Ecco la risposta, nel caso in cui il link non è più valido:

Se si utilizza layout personalizzato nella vista raccolta, controllare se la sua origine dati è pari a zero in:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 

Il risultato dovrebbe essere qualcosa di simile:

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 
    if (self.collectionView.dataSource != nil) { 
     // Your layout code  
     return array; 
    } 
    return nil; 
} 

Questo cambiamento risolve il seguente problema:

  • Assertion failure in -[UICollectionView _createPreparedSupplementaryViewForElementOfKind:atIndexPath:withLayoutAttributes:applyAttributes:]

è anche possibile controllare il seguente argomento, tuttavia non ha risolto nulla nel mio caso:

Removing empty space, if the section header is hidden in the UICollectionView

spero che ti aiuterà e non sprecheresti tanto tempo quanto me.

+1

@ChrisLoonam - qui vai – Michael

0

Prova questa:

self.collectionView?.dataSource = nil 
self.collectionView = nil 

Ha funzionato per me;)

1

Questa risposta è simile agli altri in cui si crea un metodo che controlla l'origine dei dati, ma è un po 'più semplice. Sembra che il problema sia legato al layout della vista dell'insieme che si attacca dopo che la raccolta è stata rilasciata. Così ho azzerato le proprietà del layout come sotto e l'errore è scomparso.

deinit { 
    let layout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout 
    layout.estimatedItemSize = CGSizeZero 
    layout.sectionInset = UIEdgeInsetsZero 
    layout.headerReferenceSize = CGSizeZero 
} 
+0

Puoi confermarlo come un bug o ci manca qualcosa? –

+0

È sicuramente un bug a un certo livello - possibile solo nei documenti. Di solito quando registro un bug come questo con Apple (che dovresti fare) dirò che il valore atteso dovrebbe essere diverso "o la documentazione dovrebbe essere più chiara" –

0

Ho continuato a ottenere lo stesso errore. Avevo impostato CustomHeaderView per la mia collezioneView. Ho avuto la classe della Raccolta riutilizzabile vista su CustomHeaderView e ho impostato l'identificatore. Ho 1/2 ora cercando di capire perché questo stava fallendo.

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindSectionFooter with identifier SectionHeader - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

È necessario leggere attentamente i registri ... lezione appresa.

'could not dequeue a view of kind: UICollectionElementKindSectionFooter

Il motivo è perché In storyboard - in Identity ispettore CollectionView avevo controllato entrambe Accessori: Sezione Intestazione e piè di pagina Sezione. Mi serviva solo l'intestazione della sezione. Basta deselezionare il piè di pagina ... crea ed esegui..BOOM!

0

Un bug iOS9, in dealloc setloc livello delegato nil di viewcontroller.

- (void)dealloc{ 

    if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"9"]) { 
     self.collectionView.layer.delegate = nil; 
    } 
} 
Problemi correlati