2014-09-11 19 views
10

Mentre so che scrollViews annidate non sono l'ideale, i nostri progettisti mi hanno fornito questa configurazione, quindi sto facendo del mio meglio per farlo funzionare. Cominciamo!Scorrimento verticale continuo tra UICollectionView nidificato in UIScrollView

Visualizza gerarchia

  • UIView
    • UIScrollView (scorrimento verticale solo)
      • UIImageView
      • UICollectionView # 1 (scorrimento orizzontale solo)
      • UIImageView (diverso dal UIImageView precedente) (Solo scorrimento verticale)
      • UICollectionView # 2

Nota importante

Tutti i miei punti di vista sono definite utilizzando programmatico Layout automatico. Ogni vista successiva nella gerarchia di sottoriport di UIScrollView ha una dipendenza della coordinata y sulla vista precedente.

Il problema

Per semplicità, modifichiamo nomenclatura un bit:

  • _outerScrollView farà riferimento a UIScrollView
  • _innerScrollView farà riferimento UICollectionView #2

Mi piacerebbe il mio _outerScrollView per instradare il suo evento di tocco su _innerScrollView al raggiungimento della parte inferiore del suo contenuto Dimensione. Vorrei che accadesse il contrario quando eseguivo il backup.

Attualmente, ho il codice seguente:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
{ 
    CGFloat bottomEdge = [scrollView contentOffset].y + CGRectGetHeight(scrollView.frame); 
    if (bottomEdge >= [_outerScrollView contentSize].height) { 
     _outerScrollView.scrollEnabled = NO; 
     _innerScrollView.scrollEnabled = YES; 
    } else { 
     _outerScrollView.scrollEnabled = YES; 
     _innerScrollView.scrollEnabled = NO; 
    } 
} 

dove le condizioni iniziali (prima di qualsiasi scorrimento) è impostato:

outerScrollView.scrollEnabled = YES; 
innerScrollView.scrollEnabled = NO; 

Cosa accade?

dopo aver toccato la vista, le outerScrollView scorre fino alla sua bordo inferiore, e poi ha un effetto elastico a causa di _outerScrollView.bounces = YES; Se tocco di nuovo la vista, il rotolo innerScrollView fino a raggiungere il bordo inferiore. Al ritorno, lo stesso effetto di banding di gomma avviene nell'ordine inverso. Quello che voglio succedere è avere un movimento fluido tra le due sottoview.

Ovviamente, ciò è dovuto alle condizioni scrollEnabled impostate nel condizionale nel frammento di codice. Quello che sto cercando di capire è come indirizzare la velocità/velocità di una scrollView alla successiva scrollView al raggiungimento di un bordo.

Qualsiasi assistenza in questo numero sarebbe molto apprezzata.

Altre note

  1. Questo non ha funzionato per me: https://github.com/ole/OLEContainerScrollView
  2. Sto pensando di mettere tutto nella gerarchia UIScrollView (tranne che per UICollectionView # 2) all'interno UICollectionView # 2supplementaryView. Non sono sicuro che funzionerebbe.
+0

Sono stato indirizzato al seguente video da un conoscente su Twitter: http://asciiwwdc.com/2013/sessions/217. Lo sto verificando ora. – ArtSabintsev

+1

Quanto è alto '_innerScrollView'? Intendo il suo 'frame', non il suo' contentSize'. È alto come lo schermo? O è più corto dello schermo, così quando è completamente sullo schermo, parte della vista dell'immagine è ancora visibile? Inoltre, quale layout stai usando per '_innerScrollView'? –

+0

Ho finito per capirlo. Per rispondere alla tua domanda, la cornice di innerScrollView è la larghezza del dispositivo e circa 1/3 dell'altezza della vista principale di viewController. – ArtSabintsev

risposta

6

Capito!

Primo:

_scrollView.pagingEnabled = YES;

Secondo:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
{ 
    if (scrollView == _scrollView || scrollView == _offersCollectionView) { 

     CGFloat offersCollectionViewPosition = _offersCollectionView.contentOffset.y; 
     CGFloat scrollViewBottomEdge = [scrollView contentOffset].y + CGRectGetHeight(scrollView.frame); 

     if (scrollViewBottomEdge >= [_scrollView contentSize].height) { 
      _scrollView.scrollEnabled = NO; 
      _offersCollectionView.scrollEnabled = YES; 
     } else if (offersCollectionViewPosition <= 0.0f && [_offersCollectionView isScrollEnabled]) { 
      [_scrollView scrollRectToVisible:[_scrollView frame] animated:YES]; 
      _scrollView.scrollEnabled = YES; 
      _offersCollectionView.scrollEnabled = NO; 
     } 
    } 
} 

Dove:

  • _scrollView è la _outerScrollView
  • _offersCollectionView è il _innerScrollView (che era UICollectionView # 2 nel mio post originale).

Ecco cosa succede ora:

  • Quando scorrere verso l'alto (e quindi la vista si sposta verso il basso), il offersCollectionView subentra l'intera vista, spostando le altre subviews fuori dalla vista.
  • Se scorro verso il basso (quindi le visualizzazioni), il resto delle sottoview torna a essere attivo con l'effetto di rimbalzo della scrollView.
1

La risposta accettata non ha funzionato per me. Ecco cosa ha fatto:

Definire una sottoclasse di UIScrollView:

class CollaborativeScrollView: UIScrollView, UIGestureRecognizerDelegate { 

    var lastContentOffset: CGPoint = CGPoint(x: 0, y: 0) 

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { 
     return otherGestureRecognizer.view is CollaborativeScrollView 
    } 
} 

Poiché non è possibile reindirizzare tocchi per un'altra vista, l'unico modo per garantire che lo ScrollView esterno può continuare a scorrere una volta quello interno ferma viene se avesse ricevuto i tocchi per tutto il tempo. Tuttavia, per evitare che quello esterno si muova mentre quello interno è, dobbiamo bloccarlo senza impostare il suo isScrollEnabled a false, altrimenti smetterà di ricevere i tocchi e non sarà in grado di riprendere dove quello interno lasciato fuori quando vogliamo scorrere oltre l'interno in alto o in basso.

Ecco fatto assegnando un UIScrollViewDelegate alle scrollviews, e l'attuazione di scrollViewDidScroll(_:) come mostrato:

class YourViewController: UIViewController, UIScrollViewDelegate { 

    private var mLockOuterScrollView = false 

    @IBOutlet var mOuterScrollView: CollaborativeScrollView! 
    @IBOutlet var mInnerScrollView: CollaborativeScrollView! 

    enum Direction { 
     case none, left, right, up, down 
    } 

    func viewDidLoad() { 
     mOuterScrollView.delegate = self 
     mInnerScrollView.delegate = self 
     mInnerScrollView.bounces = false 
    } 

    func scrollViewDidScroll(_ scrollView: UIScrollView) { 
     guard scrollView is CollaborativeScrollView else {return} 
     let csv = scrollView as! CollaborativeScrollView 

     //determine direction of scrolling 
     var directionTemp: Direction? 
     if csv.lastContentOffset.y > csv.contentOffset.y { 
      directionTemp = .up 
     } else if csv.lastContentOffset.y < csv.contentOffset.y { 
      directionTemp = .down 
     } 
     guard let direction = directionTemp else {return} 

     //lock outer scrollview if necessary 
     if csv === mInnerScrollView { 
      let isAlreadyAllTheWayDown = (mInnerScrollView.contentOffset.y + mInnerScrollView.frame.size.height) == mInnerScrollView.contentSize.height 
      let isAlreadyAlltheWayUp = mInnerScrollView.contentOffset.y == 0 
      if (direction == .down && isAlreadyAllTheWayDown) || (direction == .up && isAlreadyAllTheWayUp) { 
       mLockOuterScrollView = false 
      } else { 
       mLockOuterScrollView = true 
      } 
     } else if mLockOuterScrollView { 
      mOuterScrollView.contentOffset = mOuterScrollView.lastContentOffset 
     } 

     csv.lastContentOffset = csv.contentOffset 
    } 
} 

E questo è tutto. Ciò impedirà lo scrollview esterno dello scrolling quando inizi a scorrere quello interno, e lo raccogli di nuovo quando l'interno viene fatto scorrere fino a una delle sue estremità.

Problemi correlati