Ich kann nicht mit den iOS 5.xv 6.x Unterschieden sprechen, aber wenn ich CADisplayLink
verwende, programmiere ich niemals Code wie "move x pixels/points" bei jeder Iteration, sondern schaue auf die timestamp
(oder genauer gesagt, das Delta zwischen meinem ersten timestamp
und dem aktuellen timestamp
) und berechnen die Position auf der Grundlage, wie viel Zeit vergangen ist, nicht, wie viele Frames bestanden haben. Auf diese Weise beeinflussen Bildraten nicht die Geschwindigkeit der Bewegung, sondern nur die Glätte. (Und der Unterschied zwischen 30 und 29 wahrscheinlich nicht zu unterscheiden sein.)
Zitat aus den CADisplayLink Class Reference:
Sobald der Display-Link mit einer Laufschleife zugeordnet ist, wird der Wähler auf dem Ziel aufgerufen, wenn Der Inhalt des Bildschirms muss aktualisiert werden. Das Ziel kann lesen Sie die timestamp Eigenschaft Display Link, um die Zeit abzurufen, die der vorherige Rahmen angezeigt wurde. Beispielsweise kann eine Anwendung, die Filme anzeigt, den Zeitstempel verwenden, um zu berechnen, welcher Videoframe als nächstes angezeigt wird. Eine Anwendung, die eigene Animationen ausführt, verwendet möglicherweise den Zeitstempel, um zu bestimmen, wo und wie angezeigte Objekte im nächsten Frame angezeigt werden. Die Eigenschaft duration bietet die Zeit zwischen Frames. Sie können diesen Wert in Ihrer Anwendung verwenden, um die Bildrate der Anzeige, die ungefähren Zeit, dass der nächste Frame angezeigt wird, zu berechnen, und die Zeichnungsverhalten einzustellen, so dass der nächste Rahmen in der Zeit vorbereitet wird, angezeigt werden.
Als Zufalls Beispiel here Ich bin ein UIBezierPath
mit der Anzahl der Sekunden Animieren, der als Parameter vergangen sind.
Oder alternativ, wenn Sie mit einer Folge von UIImage
Frames zu tun haben, könnten Sie die Rahmennummer wie folgt berechnen:
@property (nonatomic) CFTimeInterval firstTimestamp;
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.firstTimestamp)
self.firstTimestamp = displayLink.timestamp;
CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
NSInteger frameNumber = (NSInteger)(elapsed * kFramesPerSecond) % kMaxNumberOfFrames;
// now do whatever you want with this frame number
}
Oder, noch besser, einen Rahmen zu vermeiden, riskieren zu verlieren, gehen Sie voran und lassen Sie dies bei 60 fps laufen und bestimmen Sie nur, ob der Rahmen aktualisiert werden muss, und auf diese Weise reduzieren Sie das Risiko, einen Rahmen fallen zu lassen.
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.firstTimestamp)
self.firstTimestamp = displayLink.timestamp;
CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
NSInteger frameNumber = (NSInteger)(elapsed * kFramesPerSecond) % kMaxNumberOfFrames;
if (frameNumber != self.lastFrame)
{
// do whatever you want with this frame number
...
// now update the "lastFrame" number property
self.lastFrame = frameNumber;
}
}
Aber häufig sind Rahmennummern nicht benötigt.Um zum Beispiel eine UIView
in einem Kreis zu bewegen, könnten Sie so etwas wie:
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.firstTimestamp)
self.firstTimestamp = displayLink.timestamp;
CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
self.animatedView.center = [self centerAtElapsed:elapsed];
}
- (CGPoint)centerAtElapsed:(CFTimeInterval)elapsed
{
CGFloat radius = self.view.bounds.size.width/2.0;
return CGPointMake(radius + sin(elapsed) * radius,
radius + cos(elapsed) * radius);
}
By the way, wenn Sie Instrumente verwenden Framerate zu messen, kann es langsamer erscheinen, als es auf wirklich sein wird, Ein Gerät. Um die genauen Frameraten zu ermitteln, sollten Sie Matt's Kommentar programmatisch auf einem tatsächlichen Gerät mit einem Release-Build messen.
Tolle Idee! Also, auf der onTick-Methode, ich Timestamp, dann auf der nächsten, ich Timestamp wieder - dann vergleichen, um zu sehen, ob ich 0,03333 Sekunden Unterschied? Was wenn ich es nicht tue? Können Sie Ihr Konzept näher erläutern? – objectiveccoder001
@ objectcoder001 Wenn es einen Grund gibt, warum du unbedingt 30 fps brauchst, dann könntest du so etwas machen. Sehen Sie sich mein Codebeispiel an, das die Bildnummer basierend auf der verstrichenen Zeit bestimmen kann. Bei vielen Animationen müssen Sie das nicht tun, sondern Sie können einfach die neue Position basierend auf der verstrichenen Zeit berechnen, und es gibt keinen Grund, warum sie auf 30 fps beschränkt ist (vs 29 vs 59 vs etc.). – Rob
FANTASTISCH! Ich danke dir sehr. Was sind kMaxNumberOfFrames? – objectiveccoder001