2013-03-12 6 views
8

Ich habe zwei Ansichten: A und B. A ist am oberen Rand des Bildschirms positioniert, B ist am unteren Rand des Bildschirms positioniert. Wenn der Benutzer einen Knopf drückt, animiert B aufwärts mit einer EaseInEaseOut Bezier-Kurve, bis er y = 0 erreicht. Während B auf dem Weg zu seinem Ziel ist, sollte es A nach oben drücken, wenn es auf A trifft. Mit anderen Worten Wenn B beim Übergang von unten nach oben eine bestimmte y-Koordinate (A's Ursprung + Höhe) passiert hat, sollte A bei B bleiben, so scheint es, dass B A nach oben drückt."Push" Animation in Objective-C

Was ich bisher versucht:

  • Registrieren Sie ein Ziel + Selektor auf einen CADisplayLink unmittelbar nachdem der Benutzer die Taste gedrückt wird. Fordern Sie in diesem Selektor die Y-Koordinate von B an, indem Sie auf seine presentationLayer zugreifen und die y-Koordinate von A entsprechend anpassen. Diese Methode erweist sich jedoch als nicht genau genug: Der Rahmen von presentationLayer befindet sich hinter der aktuellen Position von B auf dem Bildschirm (wahrscheinlich, weil PresentationLayer die Position der animierenden Ansicht für die aktuelle Zeit neu berechnet, die länger als 1 Frame dauert). . Wenn ich die Animationsdauer von B verlängere, funktioniert diese Methode einwandfrei.
  • Registrieren Sie einen Ziel + Selektor auf einen CADisplayLink, unmittelbar nachdem der Benutzer die Schaltfläche gedrückt hat. Berechnen Sie in diesem Selektor die aktuelle y-Koordinate von B, indem Sie die Bezier-Gleichung für x = verstrichene Zeit/Animationsdauer (die die zurückgelegte Quotiententfernung/Gesamtstrecke zurückgeben soll) lösen. Ich habe Apples Open Source UnitBezier.h dafür verwendet (http://opensource.apple.com/source/WebCore/WebCore-955.66/platform/graphics/UnitBezier.h). Die Ergebnisse sind jedoch nicht korrekt.

Irgendwelche Vorschläge, was ich als nächstes versuchen kann?

Antwort

2

Sie haben gesagt, dass Sie die Technik "B animieren und Anzeigeverbindung verwenden, um A zu aktualisieren" ausprobiert haben und dass "A" hinter "B" zurückgeblieben ist. Sie könnten theoretisch eine neue Ansicht "C" animieren und dann die Frames von B und A in der Display-Verknüpfung entsprechend anpassen, wodurch Verzögerungen (relativ zueinander) eliminiert werden sollten.

+0

Brillante und äußerst einfache Lösung. Vielen Dank! – datwelk

4

Zwei einfache Lösungen:

  1. Verwenden animationWithDuration nur: Sie Ihre Animation in zwei verschachtelte Animationen brechen können, mit „Leichtigkeit in“ das Verschieben von „B“ animieren bis zu „A“, und dann Verwenden Sie "ease out", um die Bewegung von "B" und "A" den Rest des Weges zu animieren. Der einzige Trick besteht darin, sicherzustellen, dass die beiden duration Werte sinnvoll sind, damit sich die Geschwindigkeit der Animation nicht zu ändern scheint.

    CGFloat animationDuration = 0.5; 
    CGFloat firstPortionDistance = self.b.frame.origin.y - (self.a.frame.origin.y + self.a.frame.size.height); 
    CGFloat secondPortionDistance = self.a.frame.size.height; 
    CGFloat firstPortionDuration = animationDuration * firstPortionDistance/(firstPortionDistance + secondPortionDistance); 
    CGFloat secondPortionDuration = animationDuration * secondPortionDistance/(firstPortionDistance + secondPortionDistance); 
    
    [UIView animateWithDuration:firstPortionDuration 
             delay:0.0 
            options:UIViewAnimationOptionCurveEaseIn 
           animations:^{ 
            CGRect frame = self.b.frame; 
            frame.origin.y -= firstPortionDistance; 
            self.b.frame = frame; 
           } 
           completion:^(BOOL finished) { 
            [UIView animateWithDuration:secondPortionDuration 
                  delay:0.0 
                 options:UIViewAnimationOptionCurveEaseOut 
                 animations:^{ 
                  CGRect frame = self.b.frame; 
                  frame.origin.y -= secondPortionDistance; 
                  self.b.frame = frame; 
    
                  frame = self.a.frame; 
                  frame.origin.y -= secondPortionDistance; 
                  self.a.frame = frame; 
                 } 
                 completion:nil]; 
           }]; 
    
  2. können Sie lassen animateWithDuration die volle Animation von „B“ verarbeiten, aber dann CADisplayLink verwenden und presentationLayer verwenden B aktuellen frame abrufen und entsprechend A-Rahmen anzupassen:

    [self startDisplayLink]; 
    [UIView animateWithDuration:0.5 
             delay:0.0 
            options:UIViewAnimationOptionCurveEaseInOut 
           animations:^{ 
            CGRect frame = self.b.frame; 
            frame.origin.y = self.a.frame.origin.y; 
            self.b.frame = frame; 
           } 
           completion:^(BOOL finished) { 
            [self stopDisplayLink]; 
           }]; 
    

    wo die Methoden zum Starten, Stoppen und Behandeln der Anzeigeverbindung sind wie folgt definiert:

    - (void)startDisplayLink 
    { 
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)]; 
        [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    } 
    
    - (void)stopDisplayLink 
    { 
        [self.displayLink invalidate]; 
        self.displayLink = nil; 
    } 
    
    - (void)handleDisplayLink:(CADisplayLink *)displayLink 
    { 
        CALayer *presentationLayer = self.b.layer.presentationLayer; 
    
        if (presentationLayer.frame.origin.y < (self.a.frame.origin.y + self.a.frame.size.height)) 
        { 
         CGRect frame = self.a.frame; 
         frame.origin.y = presentationLayer.frame.origin.y - self.a.frame.size.height; 
         self.a.frame = frame; 
        } 
    } 
    
+0

In ähnlichen Situationen, ich habe mit einem Ansatz gegangen, wo beide Ansichten über die volle Distanz animiert sind, aber mit einem CAAnimationGroup mit einem timeoffset und beginTime für die Animation von A, um zu verhindern, dass sie tatsächlich angezeigt wird, bis B sie trifft. (Siehe http://wangling.me/2011/06/time-warp-in-imanagement.html) Ihre Lösungen klingen jedoch einfacher. –

0

Sie können followin algorythm versuchen:

1) Setzen Sie A und B in UIView (d UIView * gropedView)

2) Veränderung B.y bis wird es gleich A.y + A sein.Höhe (so wird B unter dem A richtig sein)

3) Animate groupedView

Verwandte Themen