2014-05-21 31 views
7

Ho un UICollectionView che implementa un layout basato su griglia personalizzato UICollectionViewCells. Per consentire alle celle di rispondere al trascinamento, aggiungo singolarmente uno UIPanGestureRecognizer a ogni cella.Come passare il gesto di pan a UICollectionVIew da UICollectionViewCell?

I UICollectionView scorre ancora (in orizzontale) quando tocco verso il basso e scorrere verso sinistra/destra a partire da punti tra le cellule, ma finché il gesto riconoscitore pentola viene aggiunto a una cella, sembra che la CollectionView rifiuta di scorrere quando ho inizia il mio scorrimento toccando all'interno di una cella.

In questo momento, separo i trascinamenti orizzontale sinistro/destro dai trascinamento verticale verso l'alto/il basso, quindi non ci dovrebbero essere conflitti tra il trascinamento delle celle (scorrimento verticale) e lo scorrimento dello CollectionView (scorrimento orizzontale). In questo caso, come posso passare lo scorrimento alla vista raccolta/scorrimento in modo che sappia scorrere normalmente? È davvero fastidioso dover iniziare sul confine o sulla spaziatura tra le celle.

Una volta rimosso il movimento di panoramica da una cella, lo scorrimento funziona normalmente, non importa se si inizia a scorrere su una cella o tra una cella e l'altra.

EDIT: desiderata comportamento gesto pan postato qui sotto come codice corrente

// Handle pans by detecting swipes: 
-(void) handlePan:(UIPanGestureRecognizer*)recognizer 
{ 
    // Calculate touch location 
    CGPoint touchXY = [recognizer locationInView:masterWindowView]; 

    // Handle touch 
    if (recognizer.state == UIGestureRecognizerStateBegan) 
    { 
     gestureWasHandled = NO; 
     pointCount = 1; 
     startPoint = touchXY; 
    } 

    if (recognizer.state == UIGestureRecognizerStateChanged) 
    { 
     ++pointCount; 

     // Calculate whether a swipe has occurred 
     float dX = deltaX(touchXY, startPoint); 
     float dY = deltaY(touchXY, startPoint); 

     BOOL finished = YES; 
     if ((dX > kSwipeDragMin) && (ABS(dY) < kDragLimitMax)) { 
      touchType = TouchSwipeLeft; 
      NSLog(@"LEFT swipe detected"); 
      [recognizer requireGestureRecognizerToFail:recognizer]; 
      //[masterScrollView handlePan] 
     } 
     else if ((dX < -kSwipeDragMin) && (ABS(dY) < kDragLimitMax)) { 
      touchType = TouchSwipeRight; 
      NSLog(@"RIGHT swipe detected"); 
      [recognizer requireGestureRecognizerToFail:recognizer]; 
     } 
     else if ((dY > kSwipeDragMin) && (ABS(dX) < kDragLimitMax)) { 
      touchType = TouchSwipeUp; 
      NSLog(@"UP swipe detected"); 
     } 
     else if ((dY < -kSwipeDragMin) && (ABS(dX) < kDragLimitMax)) { 
      touchType = TouchSwipeDown; 
      NSLog(@"DOWN swipe detected"); 
     } 
     else 
      finished = NO; 

     // If unhandled and downward, produce a new draggable view 
     if (!gestureWasHandled && finished && (touchType == TouchSwipeDown)) 
     { 

      [self.delegate cellBeingDragged:self]; 
      dragView.center = touchXY; 
      dragView.hidden = NO; 
      dragView.backgroundColor = [UIColor clearColor]; 


      masterScrollView.scrollEnabled = NO; // prevent user from scrolling during 
      gestureWasHandled = YES; 
     } 
     else if (gestureWasHandled) 
     { 
      // allow continued dragging after detection 
      dragView.center = touchXY; 
     } 
    } 

    if (recognizer.state == UIGestureRecognizerStateEnded) 
    { 
     // ensure that scroll view returns to scrollable 
     if (gestureWasHandled) { 
      [self.delegate cell:self dragEndedAt:touchXY]; 
     } 
    } 
} 

// Allow simultaneous recognition 
-(BOOL) gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer 
{ 
    return YES; 
} 

Questo codice funziona quando somministrato ad ogni singola cella. NON funziona se collegato a UICollectionView come riconoscitore di gesti e in effetti interrompe lo scorrimento.

+0

Dov'è questo codice? Il codice del tuo riconoscitore di gesti dovrebbe risiedere nel tuo controller di visualizzazione. Il metodo 'gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer' consente l'esecuzione simultanea di due diversi gesti, ** non ** un gesto per essere riconosciuti da due diversi punti di vista - è questo che intendi? – KerrM

risposta

8

Invece di associare un UIPanGestureRecognizer a ciascuna cella (che farà diminuire le prestazioni) aggiungere un UIPanGestureRecognizer al UICollectionView e quando il movimento pan accade utilizzare locationInView per ottenere il punto nel UICollectionView dove la padella avviato, e quindi indexPathForItemAtPoint che ritornerà tu il percorso dell'indice per la cella che dovresti animare.

In questo modo, si avrà un solo riconoscitore di gesti (buono!) Per l'intera vista dell'insieme mantenendo anche il controllo nel proprio controller di visualizzazione (come desiderato) - doppia vittoria!

Utilizzando questa soluzione, nel vostro controller della vista si implementa gestureRecognizer:shouldReceiveTouch:, afferrare la data gestureRecognizer, assicurarsi che sia il vostro UIPanGestureRecognizer e usare il suo metodo di translationInView: per scoprire se la traduzione è sulla X o Y. Utilizzare tali informazioni per decidere se si desidera restituire SÌ o NO. Per esempio:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { 
    if([gestureRecognizer isEqual:myTapGesture]) { 
    CGPoint point = [gestureRecognizer translationInView:self.collectionView]; 
    if(point.x != 0) { //adjust this condition if you want some leniency on the X axis 
     //The translation was on the X axis, i.e. right/left, 
     //so this gesture recognizer shouldn't do anything about it 
     return NO; 
    } 
    } 
    return YES; 
} 
+0

Ho provato questo e UICollectionView ha smesso di scorrere interamente, oltre a non rilevare i miei colpi su ogni singola cella. Sono tornato al mio approccio originale, che almeno mi consente di scorrere toccando le icone! – Cindeselia

+0

Mostra del codice su ciò che hai provato e su come hai implementato la soluzione che ho proposto. Dovrei aggiungere che dovresti aver implementato il protocollo 'UIGestureRecognizerDelegate' (in particolare 'gestureRecognizer: shouldReceiveTouch:') per decidere se una cella debba ricevere il gesto o meno. – KerrM

+0

In realtà, sì, sarebbe di grande aiuto conoscere le funzioni dei delegati che devo sovrascrivere e se sovrascriverle su ViewController, UICollectionView, UICollectionViewFlowLayout o UICollectionViewCell. Ho già sovrascritto handleGestureSimultaneamente per restituire sempre SÌ. Inserirà il codice qui in un momento – Cindeselia

5

Avere la -shouldReceiveTouch: e -shouldRecognizeSimultaneouslyWithGestureRecognizer: ritorno SI, aggiungi UIGestureRecognizerDelegate come l'elenco del protocollo di classe e delegano tuoi gesti delegare a sé in -viewDidLoad.

yourGesture.delegate = self; 
+0

@Cindeselia è la risposta che perde per essere accettata? –

+0

La risposta più semplice che ho potuto trovare in tutto SO. Grazie uomo! –