2014-09-26 8 views
27

Ich implementierte ein benutzerdefiniertes Aktualisierungssteuerelement (meine eigene Klasse, keine Unterklasse) und aus irgendeinem Grund seit dem Verschieben auf iOS 8 das contentInset der Bildlaufansicht (speziell UICollectionView) zu starten Aktualisierungsanimation verursacht einen seltsamen Sprung/Stottern. Hier ist mein Code:Animieren von UIScrollView contentInset verursacht Sprungstottern

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

Grundsätzlich, sobald der Benutzer Versionen zu aktualisieren, ich animieren die contentInset auf die Höhe der Refresh-Steuer. Ich denke, die Animation würde Stottern/Juckreiz reduzieren, was sie in iOS 7 getan hat. Aber in iOS 8, wenn die scrollView vom Ziehen befreit wird, anstatt nur zum contentInset zu animieren, springt der Inhalt der Bildansicht ab dem Zeitpunkt der Veröffentlichung wirklich nach unten schnell und dann animiert reibungslos. Ich bin mir nicht sicher, ob das ein Fehler in iOS 8 oder was ist. Ich habe auch versucht, hinzuzufügen:

scrollView.contentOffset = CGPointZero; 

im Animationsblock, der nichts geändert hat.

Hat jemand irgendwelche Ideen? Jede Hilfe würde sehr geschätzt werden. Vielen Dank!

Antwort

23

änderte ich die Methode mit meiner Animation Block:

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

für mich gearbeitet! Du schaukelst. Danke, dass Sie das hier eingefügt haben. – boztalay

+2

Sie haben Recht, dies behebt das Problem. Es sieht so aus, als ob die animation allein durch die Animation der contentInset die Verzögerungs-Animation beeinflusst, weshalb ein "Sprung" erscheint. Mit dem contentOffset wird die Animation von der aktuellen Position gestartet. –

+0

Das Einfügen des Inhaltsversatzes in der Animation scheint ziemlich schwer zu erraten. Wie hast du es herausgefunden? – Tudorizer

2

hatte ich das gleiche Problem, und zog meine Animation Block der ...

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView

Delegatmethode statt. Nicht perfekt, aber ich kann das Problem noch nicht genau bestimmen. Sieht so aus, als ob scrollViews -layoutSubviews Methode häufiger unter iOS8 aufgerufen wird, was jumpy Animationen verursacht.

+0

Ich versuchte es in dort zu bewegen, aber es scheint nicht die gewünschte Wirkung zu geben, leider ... – ryanthon

+1

Diese Lösung für mich gearbeitet. Um genau zu sein, zog ich meine Einstellung 'scrollView.contentInset' (innerhalb eines' animateWithDuration: ') von' scrollViewDidEndDragging: willDecelerate: 'auf' 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]; 
      }]; 
     } 
    } 
} 

können Sie versuchen, diese, den Schlüssel benutzt zwei Animationen.

+0

Diese Antwort funktioniert für mich auf iOS9.2 – liaa

+0

In meiner App mit iOS9.0 ist kein Animationsblock erforderlich, um den Sprung zu entfernen, nur das Zurücksetzen von contentOffset nach dem Festlegen von contentInset wird den Trick machen. Wenn Sie jedoch die Scroll-Geschwindigkeit des TableView beim Ausblenden der Auffrischungsansicht steuern möchten, sind doppelte Animationsblöcke die Magie, ein Animationsblock reicht nicht aus. –

+0

Können Sie erklären, wie die doppelten Animationsblöcke funktionieren? Vielen Dank. –

2

Zwei Lösungen:

  1. disable Bounce, wenn Start Laden und Bounce aktiviert, wenn fertig geladen
  2. nach Inhalt Einsatz eingestellt wird, wenn Start geladen, bitte Inhalt mit einem konstanten Wert Offset eingestellt
+0

Umschalten Bounce funktioniert nicht. Die Einstellung von contentOffset auf den Wert vor dem Festlegen von contentInset funktioniert jedoch wie ein Charm. Kein Animationsblock ist erforderlich. Die Ursache dieses Problems ist, wenn contentInset gesetzt ist, contentOffset wird auch auf einen Wert entsprechend dem neuen Wert von contentInset gesetzt. Setzen Sie also contentOffset auf seinen alten Wert zurück, nachdem Sie mit contentInset das Problem gelöst haben. –

3

zu Entfernen Sie den Sprung, Ryananthons Antwort wird den Trick machen. In meiner App mit iOS9.0 wird kein Animationsblock benötigt, um den Sprung zu entfernen, nur das Zurücksetzen von contentOffset nach dem Setzen von contentInset wird den Trick machen.

Wenn Sie die Scroll-Geschwindigkeit der TabelleView beim Ausblenden der Aktualisierungsansicht steuern möchten, Trick Trick doppelte Blöcke in user3044484 die Antwort wird die Magie tun, ist ein Animationsblock nicht genug.

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

Kann jemand erklären, wie die doppelten Animationsblöcke funktionieren? –

+0

Das ist eine ziemliche Überraschung, aber das funktioniert tatsächlich, nicht sicher, wie der doppelte Animationsblock ein anderes Verhalten verursachen kann –

1

Ich habe beschlossen, von: -

  • die Bounce deaktivieren, wenn ContentInset zu contentOffsetY aktualisiert wird.
  • Verfolgen von contentOffset und Update to 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