it-swarm.com.de

Ändern Sie die Geschwindigkeit von setContentOffset: animated :?

Gibt es eine Möglichkeit, die Geschwindigkeit der Animation beim Scrollen einer UITableView mit setContentOffset: animated :? zu ändern? Ich möchte es nach oben scrollen, aber langsam. Wenn ich Folgendes versuche, werden die unteren Zellen vor dem Beginn der Animation ausgeblendet (insbesondere diejenigen, die nach dem Scrollen nicht sichtbar sind):

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
[self.tableView setContentOffset:CGPointMake(0, 0)];
[UIView commitAnimations];

Irgendein anderer Weg um dieses Problem herum? Es gibt eine private Methode _setContentOffsetAnimationDuration, die funktioniert, aber ich möchte nicht vom App Store abgelehnt werden.

36
Jordan Kay

Es gibt keinen direkten Weg, dies zu tun, und nicht so, wie Sie es geschrieben haben. Die einzige Möglichkeit, dies zu erreichen, besteht darin, die Bewegung/Animation selbst zu erstellen.

Wenn Sie beispielsweise alle 1/10 Sekunden um 1 Bildpunkt verschieben, wird eine sehr langsame Bildlaufanimation simuliert. (Da es sich um eine lineare Animation handelt, ist die Mathematik sehr einfach!)

Wenn Sie realistischer oder ausgefallener sein und einen Easy-In-Easy-Off-Effekt simulieren möchten, benötigen Sie einige Berechnungen, um einen Bezier-Pfad zu berechnen, sodass Sie beispielsweise die genaue Position alle 1/10 Sekunden kennen

Zumindest sollte der erste Ansatz nicht so schwierig sein. .__ Verwenden Sie einfach oder -performSelector:withObject:afterDelay or NSTimerswith 

-[UIScrollView setContentOffset:(CGPoint*)];`

Ich hoffe es hilft

11
nacho4d
[UIView animateWithDuration:2.0 animations:^{
    scrollView.contentOffset = CGPointMake(x, y);
}];

Es klappt.

90
TK189

Ich habe die Antwort von nacho4d genommen und den Code implementiert. Ich dachte, es wäre hilfreich, wenn andere Leute, die zu dieser Frage kommen, Funktionscode sehen:

Ich habe meiner Klasse Mitgliedsvariablen hinzugefügt:

CGPoint startOffset;
CGPoint destinationOffset;
NSDate *startTime;

NSTimer *timer;

und Eigenschaften:

@property (nonatomic, retain) NSDate *startTime;
@property (nonatomic, retain) NSTimer *timer;

und einen Timer-Rückruf:

- (void) animateScroll:(NSTimer *)timerParam
{
    const NSTimeInterval duration = 0.2;

    NSTimeInterval timeRunning = -[startTime timeIntervalSinceNow];

    if (timeRunning >= duration)
    {
        [self setContentOffset:destinationOffset animated:NO];
        [timer invalidate];
        timer = nil;
        return;
    }
    CGPoint offset = [self contentOffset];

    offset.x = startOffset.x +
        (destinationOffset.x - startOffset.x) * timeRunning / duration;

    [self setContentOffset:offset animated:NO];
}

dann:

- (void) doAnimatedScrollTo:(CGPoint)offset
{
    self.startTime = [NSDate date];
    startOffset = self.contentOffset;
    destinationOffset = offset;

    if (!timer)
    {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
                                                      target:self
                                                    selector:@selector(animateScroll:)
                                                    userInfo:nil
                                                     repeats:YES];
    }
}

sie benötigen auch eine Timer-Bereinigung in der Dealloc-Methode. Da der Timer einen Verweis auf das Ziel (self) behält und self einen Verweis auf den Timer hat, ist wahrscheinlich auch ein Bereinigungscode zum Abbrechen/Löschen des Timers in viewWillDisappear eine gute Idee.

Alle Kommentare zu den obigen Punkten oder Verbesserungsvorschläge wären sehr willkommen, aber es funktioniert sehr gut mit mir und löst andere Probleme, die ich mit setContentOffset: animated: hatte.

14
JosephH

Das Einstellen des Inhaltsoffsets direkt hat bei mir nicht funktioniert. Das Wickeln von setContentOffset(offset, animated: false) in einen Animationsblock hat jedoch den Trick geleistet.

UIView.animate(withDuration: 0.5, animations: {
                self.tableView.setContentOffset(
               CGPoint(x: 0, y: yOffset), animated: false)
            })
7
astro4

Ich bin neugierig, ob Sie eine Lösung für Ihr Problem gefunden haben. Meine erste Idee war, einen animateWithDuration:animations:-Aufruf mit einem Block zu setzen, der das contentOffset festlegt:

[UIView animateWithDuration:2.0 animations:^{
    scrollView.contentOffset = CGPointMake(x, y);
}];

Nebenwirkungen

Obwohl dies für einfache Beispiele funktioniert, hat es auch sehr unerwünschte Nebenwirkungen. Im Gegensatz zu setContentOffset:animated: wird alles, was Sie in Delegat-Methoden tun, auch animiert, wie die scrollViewDidScroll:-Delegat-Methode.

Ich scrolle durch eine gekachelte Ansicht mit wiederverwendbaren Kacheln. Dies wird im scrollViewDidScroll: überprüft. Wenn sie wiederverwendet werden, erhalten sie eine neue Position in der Bildlaufansicht. Dies wird jedoch animiert, sodass sich durch die Ansicht Kacheln animieren. Sieht cool aus, ist aber völlig nutzlos. Ein weiterer unerwünschter Nebeneffekt ist, dass ein möglicher Treffertest der Kacheln und die Grenzen meiner Bildlaufansicht sofort unbrauchbar werden, da sich das contentOffset bereits an einer neuen Position befindet, sobald der Animationsblock ausgeführt wird. Dies bewirkt, dass Elemente erscheinen und verschwinden, solange sie noch sichtbar sind, und wo sie früher außerhalb der Grenzen der Bildlaufansicht aktiviert wurden.

Bei setContentOffset:animated: ist dies alles nicht der Fall. Anscheinend verwendet UIScrollView intern nicht dieselbe Technik.

Gibt es jemanden mit einem anderen Vorschlag zur Änderung der Geschwindigkeit/Dauer der Ausführung von UIScrollView setContentOffset:animated:?

5
epologee

https://github.com/dominikhofmann/PRTween

unterklasse UITableview 

#import "PRTween.h"


@interface JPTableView : UITableView{
  PRTweenOperation *activeTweenOperation;
}



- (void) doAnimatedScrollTo:(CGPoint)destinationOffset
{
    CGPoint offset = [self contentOffset];

    activeTweenOperation = [PRTweenCGPointLerp lerp:self property:@"contentOffset" from:offset to:destinationOffset duration:1.5];


}
2
johndpope

Sie können die Dauer wie folgt einstellen:

scrollView.setValue (5.0, fürKeyPath: "contentOffsetAnimationDuration") scrollView.setContentOffset (CGPoint (x: 100, y: 0), animiert: true)

Auf diese Weise können Sie auch alle regulären Rückrufe von Stellvertretern erhalten.

1
eGanges

WENN Sie nur versuchen, Ihren Bildlauf zu scrollen, sollten Sie Bildlauf-Rect zu sichtbar verwenden. Ich habe diesen Code gerade ausprobiert

 [UIView animateWithDuration:.7
                      delay:0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{  
                     CGRect scrollToFrame = CGRectMake(0, slide.frame.Origin.y, slide.frame.size.width, slide.frame.size.height + kPaddingFromTop*2);
                     CGRect visibleFrame = CGRectMake(0, scrollView.contentOffset.y,
                                                      scrollView.frame.size.width, scrollView.frame.size.height);
                     if(!CGRectContainsRect(visibleFrame, slide.frame))
                         [self.scrollView scrollRectToVisible:scrollToFrame animated:FALSE];}];

und es scrollt den Bildlauf zu dem Ort, den ich für die Dauer brauche, für die ich es einstelle. Der Schlüssel setzt animate auf false. Bei der Einstellung auf true war die Animationsgeschwindigkeit der von der Methode festgelegte Standardwert

1
Esko918

Für Personen, die auch Probleme beim Verschwinden von Elementen beim Scrollen einer UITableView oder einer UICollectionView haben, können Sie die Ansicht selbst erweitern, sodass mehr sichtbare Elemente vorhanden sind. Diese Lösung wird nicht für Situationen empfohlen, in denen Sie eine große Entfernung scrollen müssen, oder wenn der Benutzer die Animation abbrechen kann. In der App, an der ich gerade arbeite, musste ich nur einen festen 100px-Bildlauf durchführen lassen.

NSInteger scrollTo = 100;

CGRect frame = self.collectionView.frame;
frame.size.height += scrollTo;
[self.collectionView setFrame:frame];

[UIView animateWithDuration:0.8 delay:0.0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{
    [self.collectionView setContentOffset:CGPointMake(0, scrollTo)];
} completion:^(BOOL finished) {
    [UIView animateWithDuration:0.8 delay:0.0 options:(UIViewAnimationOptionCurveEaseIn) animations:^{
        [self.collectionView setContentOffset:CGPointMake(0, 0)];

    } completion:^(BOOL finished) {
        CGRect frame = self.collectionView.frame;
        frame.size.height -= scrollTo;
        [self.collectionView setFrame:frame];
    }];
}];
0
Ben Groot

Ich benutze transitionWithView:duration:options:animations:completion:

        [UIView transitionWithView:scrollView duration:3 options:(UIViewAnimationOptionCurveLinear) animations:^{
        transitionWithView:scrollView.contentOffset = CGPointMake(contentOffsetWidth, 0);
    } completion:nil];

UIViewAnimationOptionCurveLinear ist eine Option, mit der Animationen gleichmäßig ausgeführt werden können.

Während ich herausfand, dass in einer Animationsdauer die Delegatmethode scrollViewDidScroll nicht aufgerufen wurde, wurde die Animation erst beendet.

0
FFur