2013-04-10 2 views
13

Desidero implementare "schede" nella mia app come le schede Safari o la ricerca in App Store.UICollectionView: cercapersone come schede di Safari o ricerca in App Store

Mostrerò all'utente una carta al centro dello schermo e una parte delle carte precedenti e successive ai lati sinistro e destro. (Vedi App Store search o Safari tabs per esempio)

Ho deciso di utilizzare UICollectionView e ho bisogno di cambiare la dimensione della pagina (non ho trovato il modo) o di implementare la propria sottoclasse di layout (non so come)?

Qualsiasi aiuto, per favore?

risposta

26

Di seguito è il modo più semplice che ho trovato per ottenere questo effetto. Implica la visualizzazione della raccolta e una visualizzazione di scorrimento extra segreta.

Impostare le viste di raccolta

  • Impostare la visualizzazione raccolta e tutti i suoi metodi di origine dei dati.
  • Inquadrare la vista di raccolta; dovrebbe estendersi per tutta la larghezza che vuoi essere visibile.
  • Impostare del contentInset vista collezione:

    _collectionView.contentInset = UIEdgeInsetsMake(0, (self.view.frame.size.width-pageSize)/2, 0, (self.view.frame.size.width-pageSize)/2); 
    

Questo aiuta a compensare le cellule in modo corretto.

Configurare lo ScrollView segreto

  • Crea una ScrollView, posizionarlo dove si vuole. Se lo desideri, puoi impostarlo su hidden.
  • Imposta la dimensione dei limiti della scrollview sulla dimensione desiderata della pagina.
  • Imposta te stesso come delegato della scrollview.
  • Impostare il valore contentSize sulla dimensione del contenuto prevista della vista raccolta.

Spostare il gesto riconoscitore

  • Aggiungere gesto riconoscitore del ScrollView segreto per la vista raccolta, e disabilitare della vista collezione gesto riconoscitore:

    [_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer]; 
    _collectionView.panGestureRecognizer.enabled = NO; 
    

Delegato

- (void) scrollViewDidScroll:(UIScrollView *)scrollView { 
    CGPoint contentOffset = scrollView.contentOffset; 
    contentOffset.x = contentOffset.x - _collectionView.contentInset.left; 
    _collectionView.contentOffset = contentOffset; 
} 

Mentre la vista di scorrimento si sposta, ottenere il suo offset e impostarlo sull'offset della vista di raccolta.

ho bloggato su questo qui, in modo da controllare questo link per gli aggiornamenti: http://khanlou.com/2013/04/paging-a-overflowing-collection-view/

+0

Questo, tuttavia, non passa selezionare ed eventi toccare correttamente attraverso alla vista insieme sottostante come di iOS7. Qualche idea? – eanticev

+1

Su iOS7 (almeno potrebbe essere stato vero prima di questo) non è necessario lo scrollview. Rileva solo i gesti di scorrimento sinistro e destro e usali per impostare l'offset della tua vista di raccolta 1 pagina avanti/indietro. – buildsucceeded

+3

Non riesco a farlo funzionare correttamente su iOS7. 'scrollViewDidScroll' di una vista di scorrimento" segreta "non vengono mai consegnati. –

-6

Il precedente è piuttosto complicato, UICollectionView è una sottoclasse di UIScrollView, quindi basta fare questo:

[self.collectionView setPagingEnabled:YES]; 

Siete tutti pronto per partire.

Vedere questo detailed tutorial.

+7

Questo non risolve il problema di avere i contenuti a sinistra e a destra visibili durante il paging, come le schede safari o la ricerca in app store. –

1

Una piccola modifica sulla risposta di Soroush, che ha fatto il trucco per me. L'unica modifica che ho fatto, invece di disabilitare il gesto:

[_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer]; 
_collectionView.panGestureRecognizer.enabled = NO; 

ho scorrimento disabili al CollectionView:

_collectionView.scrollEnabled = NO; 

Come disabilitare il gesto disattivato il gesto ScrollView segreto pure.

6

È possibile sottoclasse UICollectionViewFlowLayout e sovrascrivere in questo modo:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)contentOffset 
           withScrollingVelocity:(CGPoint)velocity 
{ 
    NSArray* layoutAttributesArray = 
    [self layoutAttributesForElementsInRect:self.collectionView.bounds]; 

    if(layoutAttributesArray.count == 0) 
     return contentOffset; 


    UICollectionViewLayoutAttributes* candidate = 
    layoutAttributesArray.firstObject; 

    for (UICollectionViewLayoutAttributes* layoutAttributes in layoutAttributesArray) 
    { 
     if (layoutAttributes.representedElementCategory != UICollectionElementCategoryCell) 
      continue; 


     if((velocity.x > 0.0 && layoutAttributes.center.x > candidate.center.x) || 
      (velocity.x <= 0.0 && layoutAttributes.center.x < candidate.center.x)) 
      candidate = layoutAttributes; 


    } 

    return CGPointMake(candidate.center.x - self.collectionView.bounds.size.width * 0.5f, contentOffset.y); 
} 

questo otterrà la cella successiva o precedente a seconda della velocità ... non si spezzerà sulla cella corrente però.

+0

Il ritorno di un diverso 'CGPoint' per l'offset tramite questo metodo delegato funziona abbastanza bene. La transizione per fermarsi sulla cella sembra abbastanza liscia. – Andrei

+0

Inoltre, sembra che il trucco per ottenere la vista di scorrimento su * snap * durante la transizione sia impostare il 'decelerationRate' della vista di raccolta su' UIScrollViewDecelerationRateFast'. Per uno snap più veloce, sembra che funzioni anche se si imposta 'decelerationRate' su qualcosa di minore di 0.990000 (che sembra essere l'attuale' UIScrollViewDecelerationRateFast'). – Andrei

0

Aggiungerò un'altra soluzione. Lo snap in atto non è perfetto (non è buono come quando è impostato il paging abilitato, ma funziona abbastanza bene).

Ho provato a implementare la soluzione Soroush, ma non funziona per me.

Perché il UICollectionView è una sottoclasse di UIScrollView risponderà ad un importante metodo di UIScrollViewDelegate che è:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView 
        withVelocity:(CGPoint)velocity 
       targetContentOffset:(inout CGPoint *)targetContentOffset 

Il targetContentOffset (un inout puntatore) ti permette di ridefinire il punto di sosta per una vista di raccolta (lo x in questo caso se si scorre orizzontalmente).

Una breve nota circa un paio di variabili che trovate di seguito:

  • self.cellWidth - questa è la larghezza tua collezione di cellule vista (si può anche hardcode lì se si vuole)

  • self.minimumLineSpacing - questa è la spaziatura minima tra le celle

  • self.scrollingObjects è la matrice di oggetti contenuti nella vista di raccolta (ho bisogno di questo principalmente per contare, per sapere quando smettere di scorrimento)

Così, l'idea è quella di implementare questo metodo nella delegato della vista raccolta, in questo modo:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView 
        withVelocity:(CGPoint)velocity 
       targetContentOffset:(inout CGPoint *)targetContentOffset 
{  
    if (self.currentIndex == 0 && velocity.x < 0) { 
     // we have reached the first user and we're trying to go back 
     return; 
    } 

    if (self.currentIndex == (self.scrollingObjects.count - 1) && velocity.x > 0) { 
     // we have reached the last user and we're trying to go forward 
     return; 
    } 

    if (velocity.x < 0) { 
     // swiping from left to right (going left; going back) 
     self.currentIndex--; 
    } else { 
     // swiping from right to left (going right; going forward) 
     self.currentIndex++; 
    } 

    float xPositionToStop = 0; 

    if (self.currentIndex == 0) { 
     // first row 
     xPositionToStop = 0; 
    } else { 
     // one of the next ones 
     xPositionToStop = self.currentIndex * self.cellWidth + (self.currentIndex + 1) * self.minimumLineSpacing - ((scrollView.bounds.size.width - 2*self.minimumLineSpacing - self.cellWidth)/2); 
    } 

    targetContentOffset->x = xPositionToStop; 

    NSLog(@"Point of stopping: %@", NSStringFromCGPoint(*targetContentOffset)); 
} 

In attesa di tutte le risposte si possono avere che rende lo scatto in posizione migliore.Devo dire anche continuo a ricerca di una soluzione migliore ...

+0

Sembra funzionare ... ma non replica "il paging abilitato" con precisione e si sente un po 'imbarazzante. –

2

@Mike M's answer a Swift ...

class CenteringFlowLayout: UICollectionViewFlowLayout { 

    override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { 

     guard let collectionView = collectionView, 
      let layoutAttributesArray = layoutAttributesForElementsInRect(collectionView.bounds), 
      var candidate = layoutAttributesArray.first else { return proposedContentOffset } 

     layoutAttributesArray.filter({$0.representedElementCategory == .Cell }).forEach { layoutAttributes in 

      if (velocity.x > 0 && layoutAttributes.center.x > candidate.center.x) || 
       (velocity.x <= 0 && layoutAttributes.center.x < candidate.center.x) { 
       candidate = layoutAttributes 
      } 
     } 

     return CGPoint(x: candidate.center.x - collectionView.bounds.width/2, y: proposedContentOffset.y) 
    } 

}