2014-09-26 5 views
27

Ho implementato un controllo di aggiornamento personalizzato (la mia classe, non una sottoclasse) e per qualche motivo dal passaggio a iOS 8, impostando contentInset della vista di scorrimento (in particolare, UICollectionView) per avviare la l'animazione di rinfresco provoca uno strano salto/balbuzie. Qui è il mio codice:Animazione di UIScrollView contentInset causa il salto balbuzie

- (void)containingScrollViewDidScroll:(UIScrollView *)scrollView 
{ 
    CGFloat scrollPosition = scrollView.contentOffset.y + scrollView.contentInset.top; 

    if(scrollPosition > 0 || self.isRefreshing) 
    { 
     return; 
    } 

    CGFloat percentWidth = fabs(scrollPosition)/self.frame.size.height/2; 

    CGRect maskFrame = self.maskLayer.frame; 

    maskFrame.size.width = self.imageLayer.frame.size.width * percentWidth; 

    [CATransaction begin]; 
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; 
    self.maskLayer.frame = maskFrame; 
    [CATransaction commit]; 
} 

- (void)containingScrollViewDidEndDragging:(UIScrollView *)scrollView 
{ 
    if((self.maskLayer.frame.size.width >= self.imageLayer.frame.size.width) && !self.isRefreshing) 
    { 
     self.isRefreshing = YES; 
     [self setLoadingScrollViewInsets:scrollView]; 
     [self startAnimation]; 
     [self sendActionsForControlEvents:UIControlEventValueChanged]; 
    } 
} 

- (void)setLoadingScrollViewInsets:(UIScrollView *)scrollView 
{ 
    UIEdgeInsets loadingInset = scrollView.contentInset; 
    loadingInset.top += self.frame.size.height; 

    UIViewAnimationOptions options = UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState; 

    [UIView animateWithDuration:0.2 delay:0 options:options animations:^ 
    { 
     scrollView.contentInset = loadingInset; 
    } 
    completion:nil]; 
} 

In sostanza, una volta l'utente rilascia per aggiornare, mi animano il contentInset all'altezza del controllo di aggiornamento. Immagino che l'animazione ridurrebbe la balbuzie/balbuzie, cosa che ha fatto in iOS 7. Ma in iOS 8, quando la scrollView viene rilasciata dal trascinamento, invece di animare semplicemente a contentInset, il contenuto della vista di scorrimento salta giù dal punto di rilascio in realtà rapidamente, e poi si anima senza intoppi. Non sono sicuro se si tratta di un bug in iOS 8 o cosa. Ho anche provato ad aggiungere:

scrollView.contentOffset = CGPointZero; 

nel blocco di animazione, che non ha cambiato nulla.

Qualcuno ha qualche idea? Qualsiasi aiuto sarebbe molto apprezzato. Grazie!

risposta

23

ho cambiato il metodo con il mio blocco animazione:

- (void)setLoadingScrollViewInsets:(UIScrollView *)scrollView 
{ 
    UIEdgeInsets loadingInset = scrollView.contentInset; 
    loadingInset.top += self.view.frame.size.height; 

    CGPoint contentOffset = scrollView.contentOffset; 

    [UIView animateWithDuration:0.2 animations:^ 
    { 
     scrollView.contentInset = loadingInset; 
     scrollView.contentOffset = contentOffset; 
    }]; 
} 
+2

Ha funzionato per me! Sei forte. Grazie per averlo inserito qui. – boztalay

+2

Hai ragione, questo risolve il problema. Sembra che l'animazione del contentInset da solo causi un'interferenza dell'animazione con l'animazione di decelerazione, motivo per cui appare un "salto". Compreso il contentOffset avvia l'animazione dalla posizione corrente. –

+0

L'inclusione del contenuto nell'animazione sembra abbastanza difficile da indovinare. Come l'hai capito? – Tudorizer

2

Ho avuto lo stesso problema, e si è trasferito il mio blocco di animazione al ...

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView

metodo delegato al posto. Non perfetto, ma non riesco ancora a individuare il problema. Sembra che il metodo -layoutSubviews di scrollView venga chiamato più spesso in iOS8, causando animazioni saltellanti.

+0

ho provato a spostare in là, ma non sembra dare l'effetto desiderato, purtroppo ... – ryanthon

+1

Questa soluzione ha funzionato per me. Per essere precisi, ho spostato la mia impostazione di 'scrollView.contentInset' (all'interno di' animateWithDuration: ') da' scrollViewDidEndDragging: willDecelerate: 'a' scrollViewWillBeginDecelerating: ' – jonsibley

5
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ 
    CGPoint point = scrollView.contentOffset; 

    static CGFloat refreshViewHeight = 200.0f; 

    if (scrollView.contentInset.top == refreshViewHeight) { 
     //openning 
     if (point.y>-refreshViewHeight) { 
      //will close 
      //必须套两层animation才能避免闪动! 
      [UIView animateWithDuration:0 animations:NULL completion:^(BOOL finished) { 
       [UIView animateWithDuration:0.25 animations:^{ 
        scrollView.contentOffset = CGPointMake(0.0f, 0.0f); 
        scrollView.contentInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f); 
       } completion:NULL]; 
      }]; 

     } 
    } 
    else{ 
     //closing 
     static CGFloat openCriticalY = 40.0f;//会执行打开的临界值 
     if(point.y<-openCriticalY){ 
      //will open 
      [UIView animateWithDuration:0 animations:NULL completion:^(BOOL finished) { 
       [UIView animateWithDuration:0.25 animations:^{ 
        scrollView.contentInset = UIEdgeInsetsMake(refreshViewHeight, 0.0f, 0.0f, 0.0f); 
        scrollView.contentOffset = CGPointMake(0.0f, -refreshViewHeight); 
       } completion:NULL]; 
      }]; 
     } 
    } 
} 

si può provare questo, la chiave sta usando due animazioni.

+0

Questa risposta funziona per me su iOS9.2 – liaa

+0

Nella mia app con iOS9.0, non è necessario alcun blocco di animazione per rimuovere il salto, basta resettare contentOffset dopo aver impostato contentInset. Tuttavia, se si desidera controllare la velocità di scorrimento della tabella VIew quando si nasconde la vista di aggiornamento, i blocchi di animazione doppia faranno la magia, un blocco di animazione non è sufficiente. –

+0

Puoi spiegare come funzionano i doppi blocchi di animazione? Grazie. –

2

due soluzioni:

  1. rimbalzo disabilitazione quando l'inizio di carico e consentire rimbalzo quando termina il caricamento
  2. dopo aver impostato contenuto inserto quando inizio carico, impostare sfalsato un valore costante
+0

L'attivazione/disattivazione del rimbalzo non funziona. Ma impostando contentOffset sul suo valore prima di impostare contentInset funziona come un incantesimo. Non è necessario alcun blocco di animazione. La causa di questo problema si verifica quando contentInset è impostato, contentOffset viene anche impostato su un valore in base al nuovo valore di contentInset. Quindi ripristinare contentOffset al suo vecchio valore dopo aver impostato contentInset risolve il problema. –

3

Al contenuto rimuovi il salto, la risposta di ryanthon farà il trucco. Nella mia app con iOS9.0, nessun blocco di animazione è nemmeno necessario per rimuovere il salto, basta resettare contentOffset dopo aver impostato contentInset.

Se si desidera controllare la velocità di scorrimento del TableView quando si nasconde la vista di aggiornamento, il doppio blocchetto di animazione blocca nella risposta dell'utente3044484 farà la magia, un blocco di animazione non è sufficiente.

if (self.tableView.contentInset.top == 0) 
{ 
    UIEdgeInsets tableViewInset = self.tableView.contentInset; 
    tableViewInset.top = -1.*kTableHeaderHeight; 
    [UIView animateWithDuration: 0 animations: ^(void){} completion:^(BOOL finished) { 
     [UIView animateWithDuration: 0.5 animations:^{ 
     //no need to set contentOffset, setting contentInset will change contentOffset accordingly. 
      self.tableView.contentInset = tableViewInset; 
     }]; 
    }]; 
} 
+0

Qualcuno può spiegare come funzionano i doppi blocchi di animazione? –

+0

Questa è piuttosto una sorpresa, ma in realtà funziona, non sono sicuro di come il doppio blocco di animazione possa causare un comportamento diverso –

1

ho risolto da: -

  • Disabilitare il rimbalzo quando ContentInset è stato aggiornato per contentOffsetY.
  • Tieni traccia di contentOffset e Aggiorna a tableView ContentInset.
var contentOffsetY:CGFloat = 100 
    func tracScrollContent(location: UIScrollView) { 
     if(location.contentOffset.y == -contentOffsetY) { 
      tblView.isScrollEnabled = true 
      tblView.bounces = false 
      tblView.contentInset = UIEdgeInsets(top: contentOffsetY, left: 0, bottom: 0, right: 0) 
     }else if(location.contentOffset.y >= 0){ 
      tblView.bounces = true 
      tblView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) 
     } 
    } 

Github Demo Swift-3