6.2 Als die Views das Laufen lernten
Für jedes Puzzleteil verwendet die App einen eigenen Imageview, wobei sie ein großes Bild in die passenden Bilder für die Teile zerschneidet. Das ist sehr praktisch, wenn Sie das Bild austauschen wollen. Sie brauchen nur zwei Bilder in jeweils der Standard- und der Retina-Auflösung in den Ressourcen auszutauschen und sie nicht noch manuell zu zerschneiden.
Dazu enthält das Programm die Kategorie UIImage(Subimage) mit zwei Methoden. Über subimageWithRect: können Sie aus einem Bild einen rechteckigen Bereich in ein neues Bild kopieren:
- (UIImage *)subimageWithRect:(CGRect)inRect {
CGImageRef theImage =
CGImageCreateWithImageInRect(self.CGImage, inRect);
UIImage *theResult = [UIImage imageWithCGImage:theImage];
CGImageRelease(theImage);
return theResult;
}
Listing 6.20 Kopieren eines rechteckigen Bereiches in ein neues Bild
Die zweite Methode, splitIntoSubimagesWithRows:columns:, zerlegt ein Bild in gleichgroße, rechteckige Bilder und liefert das Ergebnis in einem Array zurück. Das Bild enthält seine Größe als geräteunabhängige Werte. Im Puzzle liefert size also immer 300 × 300 Pixel für das Puzzlebild – egal ob es für die Standard- oder die Retina-Auflösung ist. Sie müssen also diese logische Bildgröße erst in die physikalische umrechnen, indem Sie die Breite und die Höhe mit dem Skalierungsfaktor multiplizieren. Den Faktor erhalten Sie über die Property scale der Klasse UIImage.
- (NSArray *)splitIntoSubimagesWithRows:(NSUInteger)inRows
columns:(NSUInteger)inColumns {
CGSize theSize = self.size;
CGRect theRect = CGRectMake(0.0, 0.0,
self.scale * theSize.width / inColumns,
self.scale * theSize.height / inRows);
NSMutableArray *theResult = [NSMutableArray
arrayWithCapacity:inRows * inColumns];
theSize = theRect.size;
for(NSUInteger theRow = 0; theRow < inRows; ++theRow) {
for(NSUInteger theColumn = 0; theColumn < inColumns;
++theColumn) {
theRect.origin.x = theSize.width * theColumn;
theRect.origin.y = theSize.height * theRow;
[theResult addObject:
[self subimageWithRect:theRect]];
}
}
return [theResult copy];
}
Listing 6.21 Aufteilen eines Bildes für das Puzzle
Bei der Aktualisierung des Puzzles brauchen Sie jeweils nur den Stein an seine neuen Positionen zu setzen. Das können Sie erreichen, indem Sie der Property frame des Views für das Puzzleteil einen entsprechenden Wert zuweisen. Um zu einem Puzzleteil den entsprechenden Subview zu finden, vertauscht die Methode die Views in der Reihenfolge. Dadurch entspricht die Position des Views im Subview-Array der Position des Puzzleteils im Array des Modells.
- (void)puzzleDidTilt:(NSNotification *)inNotification {
NSDictionary *theInfo = inNotification.userInfo;
NSUInteger theFromIndex = 
[[theInfo objectForKey:kPuzzleFromIndexKey] intValue];
NSUInteger theToIndex = 
[[theInfo objectForKey:kPuzzleToIndexKey] intValue];
UIView *thePuzzleView = self.puzzleView;
UIView *theFromView = 
[thePuzzleView.subviews objectAtIndex:theFromIndex];
UIView *theToView = 
[thePuzzleView.subviews objectAtIndex:theToIndex];
[thePuzzleView exchangeSubviewAtIndex:theFromIndex 
withSubviewAtIndex:theToIndex];
theFromView.frame = [self frameForItemAtIndex:theToIndex];
theToView.frame = [self frameForItemAtIndex:theFromIndex];
}
Listing 6.22 Aktualisierung der Puzzleteile
6.2.1 Animationen mit Blöcken

Mithilfe von Blöcken können Sie anfangen, Ihre Views in Bewegung zu setzen. Dazu bietet Ihnen die Klasse UIView eine Reihe von Klassenmethoden. Die Methoden operieren nicht auf Objektebene, da Sie innerhalb einer Animation mehrere Views gleichzeitig verändern können. Die Animationen beschreiben Sie dabei über Property-Veränderungen der beteiligten Views. Sie geben dazu einfach an, welchen Wert die Property am Ende des Animationsablaufs haben soll, und den Rest erledigt Cocoa für Sie. Diese Animationsbeschreibung erfolgt innerhalb eines Blocks. Die Arbeit mit Blöcken haben Sie ja bereits in Kapitel 2, »Grundlagen«, kennengelernt. Im einfachsten Fall wollen Sie nur eine oder mehrere Eigenschaften Ihrer Views verändern und das über eine Animation visualisieren. Beispielsweise können Sie folgendermaßen einen View animiert vergrößern:
CGRect theFrame = theView.frame;
theFrame.size.width *= 2;
theFrame.size.height *= 2;
[UIView animateWithDuration:0.75 animations:^{
theView.frame = theFrame;
}];
Listing 6.23 Animierte Vergrößerung eines Views
Durch diesen Code verdoppeln Sie jeweils die Breite und Höhe des Views, und Cocoa Touch visualisiert diese Änderung, indem es den View über eine Bewegung aufzieht, die eine Dreiviertelsekunde dauert. Dabei enthält dieser Code gegenüber einer nicht animierten Version nur den Aufruf der Klassenmethode animateWithDuration:animations: und den Block zusätzlich.
Parameterlose Blockfunktionen
Wenn eine Blockfunktion keinen Parameter erwartet, können Sie die Angabe der Parameterliste auch weglassen. In Listing 6.23 können Sie deshalb die Definition des Animationsblocks von ^(void){ ... } auf ^{ ... } verkürzen.
Sie können also eine Animation durch einen Methodenaufruf und eine Zeile im Animationsblock starten. Cocoa erzeugt automatisch die notwendigen Animationen zu den Änderungen, die Sie im Animationsblock an den Views vornehmen. Auf die Abläufe im Hintergrund gehen wir Abschnitt 6.3 noch genauer ein.
In vielen Fällen möchten Sie am Ende der Animation weiteren Code ausführen. Dafür gibt es die Variante animateWithDuration:animations:completion: mit zwei Blockfunktionen als Parametern:
[UIView animateWithDuration:0.75 animations:^{
theView.frame = theFrame;
}
completion:^(BOOL inFinished) {
theView.alpha = 0.5;
}];
Listing 6.24 Animation mit Block für das Animationsende
Die Animation ruft nach ihrer Beendigung den zweiten Block auf. Dabei gibt der boolesche Parameter an, ob Cocoa Touch die Animation regulär beendet oder vor der Beendigung abgebrochen hat. In der Regel hat dieser Parameter also den Wert YES. Während auch dieser Code die Größe des Views kontinuierlich ändert, setzt er die Transparenz in einem Schritt auf 50 %, weil diese Änderung ja nicht im Animationsblock steht. Wollen Sie hingegen den View synchron zur Größenänderung ausblenden lassen, müssen Sie die Anweisung theView.alpha = 0.5; vom Completion- in den Animationsblock verschieben.
Abbrechen von Animationen
Für den Abbruch von View-Animationen gibt es keine dokumentierte Methode im UIKit. Da diese Animationen jedoch auf Core Animation basieren, können Sie auf die Animationen eines Views über seinen Layer zugreifen. Die folgende Anweisung stoppt alle laufenden Animationen des Views:
[theView.layer removeAllAnimations];
Wenn Sie die Animationen so stoppen, springt der View augenblicklich in den Endzustand. Alle animierten Propertys des Views haben also die Werte, die Sie ihnen im Animationsblock zugewiesen haben.
Sie können folgende Propertys eines Views animieren:
- Mit den Propertys frame und bounds können Sie die Position und die Größe des Views verändern.
- Über die Property center verschieben Sie den Mittelpunkt eines Views. Das hat nicht nur Auswirkungen auf dessen Lage, sondern auch auf die Transformation des Views.
- Sie können einem View eine affine Transformation, das ist eine 3×3-Matrix einer bestimmten Struktur, über die Property transform zuweisen. Mit Transformationen können Sie den View beispielsweise drehen, vergrößern und verschieben.
- Ein- und Ausblendeffekte können Sie durch eine Änderung des Wertes der Property alpha erreichen.
- Sogar die Hintergrundfarbe des Views können Sie über die Property backgroundColor animieren.
- Über die Property contentStretch bestimmen Sie den dehnbaren Bereich des Views.
Dehnungsübungen
Der dehnbare Bereich eines Views ist ein Rechteck, dessen Breite und Höhe der View anpassen darf (siehe Abbildung 6.14). Allerdings kann der View auch Bereiche an den Rändern anpassen (das ist durch Pfeile in der Abbildung gekennzeichnet). Für die Koordinaten geben Sie relative Werte zwischen 0 und 1 an. Für den x-Wert entspricht also 0 dem linken und 1 dem rechten Rand, und 0,5 liegt genau in der Mitte. Analog ist 0,5 die halbe und 1 die volle Breite des Views. Dadurch sind die Größenangaben unabhängig von der Größe des Views. Das Rechteck für Abbildung 6.14 hat beispielsweise folgende Werte:
theView.contentStretch = CGRectMake(0.125, 0.25, 0.625, 0.5);
Mit diesen sieben animierbaren Propertys lässt sich schon eine Menge anstellen. Beispielsweise können Sie durch die animierte Änderung des Frames oder des Alphawertes Subviews ein- und ausblenden lassen. Die Transformationsmatrix der Property transform ist eine C-Struktur namens CGAffineTransform, die Sie über diverse Funktionen erstellen und modifizieren können. Sie hat anfänglich den Wert CGAffineTransformIdentity, der die Geometrie des Views nicht verändert. Andere Matrizen lassen sich nun auf zwei Weisen erzeugen: Entweder erzeugen Sie eine neue Matrix zu vorgegebenen Werten oder Sie ändern eine vorhandene Matrix.
Abbildung 6.14 Dehnbare Bereiche (Pfeile) eines Views
Transformationsmatrizen
Die Grundlagen für die Transformationsmatrizen oder affinen Transformationen sind ein Teilgebiet der linearen Algebra. Da die hier vorgestellten Funktionen für die meisten Anwendungsfälle ausreichen, verzichten wir auf eine genauere Darstellung.
Allerdings gibt es bei Rotationen einen kleinen Fallstrick: Die Darstellung als Matrix erlaubt nur Drehungen im Winkelbereich
von -
(-180°) bis
(180°). Winkelangaben außerhalb dieses Bereiches führen allerdings nicht zu einem
Programmfehler, sondern nur zu einer unerwarteten Drehung. Wenn Sie beispielsweise
die Matrix für eine Dreivierteldrehung (3
/ 2) gegen den Uhrzeigersinn erzeugen, führt das zu einer Vierteldrehung im Uhrzeigersinn.
Die Animation des Views nimmt also eine Abkürzung, wobei das Endergebnis allerdings
gleich ist. Kontinuierliche Rotationen lassen sich so allerdings nur sehr schwer realisieren.
Dafür verwenden Sie besser Core Animation, worauf Abschnitt 6.3 noch genauer eingeht.
Wenn Sie mehrere Transformationen, z. B. eine Rotation und eine Skalierung, auf einen View anwenden möchten, können Sie auch bestehende Transformationsmatrizen miteinander verknüpfen. Sie können dabei entweder jeweils eine der Operationen Verschieben (CGAffineTransformTranslate), Skalieren (CGAffineTransformScale) oder Drehen (CGAffineTransformRotate) auf eine Matrix anwenden. Alternativ können Sie auch über die Funktion CGAffineTransformConcat zwei Matrizen so miteinander verknüpfen, als hätten Sie die Transformationen nacheinander ausgeführt.
Das Memory-Spiel des Beispielprojekts Games lässt zwei gleiche Spielkarten durch eine halbe Drehung mit gleichzeitiger Verkleinerung verschwinden, wodurch ein Strudeleffekt entsteht. Dazu verknüpft es eine Rotation mit einer Skalierung (in Listing 6.25 hervorgehoben). Nach Beendigung der Animation versteckt es die beiden Views für die Karten und setzt die Transformationsmatrix wieder auf die Identität, damit die Karten bei einem erneuten Start des Spiels wieder die richtige Darstellung haben.
[UIView animateWithDuration:0.75
animations:^{
for(Card *theCard in theCards) {
CardView *theView = [self.memoryView.subviews
objectAtIndex:theCard.index];
theView.transform = CGAffineTransformScale(
CGAffineTransformMakeRotation(M_PI),
0.1, 0.1);
}
}
completion:^(BOOL inFinished) {
for(Card *theCard in theCards) {
CardView *theView = [self.memoryView.subviews
objectAtIndex:theCard.index];
theView.hidden = theCard.solved;
theView.transform = CGAffineTransformIdentity;
}
}];
Listing 6.25 Verknüpfung von zwei Transformationen
Während der Animationsausführung ist die Verarbeitung von Touch-Events der animierten Views unterbrochen, sodass sie keine Eingaben empfangen können. In vielen Fällen ist das auch nicht notwendig. Es gibt jedoch noch eine weitere Animationsmethode, und zwar animateWithDuration:delay:options:animations:completion:, mit der Sie unter anderem dieses Verhalten beeinflussen können. Dazu besitzt diese Methode den Parameter options. Außerdem können Sie über den Parameter delay den Ausführungsbeginn der Animation verzögern.
Der Wert des Optionsparameters ist eine Bitmenge, die Sie aus mehreren Konstanten zusammensetzen können, die einen booleschen Wert darstellen. Wenn Sie mehrere Eigenschaften über die Optionen setzen wollen, müssen Sie die entsprechenden Konstanten über den Operator für das bitweise Oder | verknüpfen.
Die Touchverarbeitung während der Animation lässt sich über die Konstante UIViewAnimationOptionAllowUserInteraction aktivieren. Über Viewanimationen können Sie Ihre Views allerdings auch kontinuierlich animieren. Dazu müssen Sie nur den Schalter UIViewAnimationOptionRepeat setzen, dann setzt die Animation am Ende der Bewegung den View wieder auf den Ursprungszustand zurück und beginnt von vorne. Dabei gibt dann der Parameter duration die Länge einer Wiederholung an, und die gesamte Animation läuft so lange, bis Sie sie explizit stoppen. Diese dauerhaften Animationen sollen häufig auch den Rückweg, also den Übergang vom End- zum Anfangszustand, animieren. Mit dem Schalter UIViewAnimationOptionAutoreverse können Sie dieses Verhalten einschalten.
Über den Optionsparameter können Sie auch den Geschwindigkeitsverlauf in der Animation steuern. Tabelle 6.4 listet die vier dafür möglichen Konstanten mit einer Beschreibung ihres Geschwindigkeitsverlaufs auf:
| UIViewAnimationOptionCurve... | Die Animation ... |
|
...EaseInOut |
beschleunigt am Anfang und bremst am Ende ab. |
|
...EaseIn |
beschleunigt am Anfang und läuft dann bis zum Ende mit einer konstanten Geschwindigkeit. |
|
...EaseOut |
startet mit einer konstanten Geschwindigkeit und verlangsamt sich am Ende. |
|
...Linear |
hat über den gesamten Verlauf die gleiche Geschwindigkeit. |
Projektinformation
Das Beispielprojekt Animation, das Sie auf der beiliegenden DVD unter Code/Apps/Animation oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_2/Apps/Animation finden, vermittelt einen Eindruck von den verschiedenen Animationsverläufen. Sie können dort über ein Segmented Control die Animationskurve auswählen und eine Animation starten.
Durch wiederholte Animationen können Sie sehr leicht die Wackelanimation erzeugen, die Sie sicherlich aus dem Springboard des iPhones kennen, wenn Sie dessen Apps bearbeiten möchten. [Falls Sie sie nicht kennen: Drücken Sie einfach ein Icon im Springboard so lange, bis alle Icons zu wackeln anfangen.] Diese Animation ist einfach eine schnelle Hin- und Zurückdrehung des Views um einen kleinen Winkel, für die Sie die Repeat- und Autoreverse-Option einschalten müssen. Außerdem sollten Sie die Ease-In-Ease-Out-Animationskurve verwenden, damit die Bewegung nicht zu abgehackt aussieht.
Damit die Animation außerdem gleichmäßig zu beiden Seiten dreht, müssen Sie den View vor der Animation mit dem negativen Winkel in die Gegenrichtung drehen, was Sie nach der Beendigung allerdings wieder zurücknehmen. Den kompletten Code für diese Animation sehen Sie in Listing 6.26:
CGFloat theAngle = 2.5 * M_PI / 180;
theView.transform = CGAffineTransformMakeRotation(-theAngle);
[UIView animateWithDuration:0.05
delay:0.0
options:UIViewAnimationOptionRepeat |
UIViewAnimationOptionAutoreverse |
UIViewAnimationOptionCurveEaseInOut
animations:^{
theView.transform =
CGAffineTransformMakeRotation(theAngle);
}
completion:^(BOOL inFinished) {
theView.transform = CGAffineTransformIdentity;
}];
Listing 6.26 Wackelanimation wie beim Bearbeiten des Springboards
Animationen ohne Blockfunktionen
Blockfunktionen hat Apple erst mit iOS 4 eingeführt. Trotzdem können Sie auch in älteren iOS-Versionen Animationen einbinden, die Sie über Aufrufe der Klassenmethoden beginAnimations:context: und commitAnimations einschließen. Mit weiteren Klassenmethoden können Sie zwischen diesen Methodenaufrufen die Animationsoptionen setzen. Die Animation aus Listing 6.23 sieht ohne Blockfunktionen beispielsweise so aus:
CGRect theFrame = theView.frame;
theFrame.size.width *= 2;
theFrame.size.height *= 2;
[UIView beginAnimations:@"resize" context:NULL];
[UIView setAnimationDuration:0.75];
theView.frame = theFrame;
[UIView commitAnimations];
Der erste Parameter der Methode beginAnimations:context: gibt den Namen der Animation an. Sie können hier auch nil verwenden. Unter diesem Namen speichert Cocoa Touch die Animation im Layer. Darauf geht Abschnitt 6.3 noch genauer ein. Im Context-Parameter können Sie der Animation beliebige Daten mitgeben, die sie an Ihre Delegate-Methoden weitergibt.
Apple hat dieses Verfahren der Animationserzeugung allerdings mit iOS 4 als veraltet markiert, und Sie sollten lieber die Klassenmethoden mit den Blockfunktionen verwenden.
6.2.2 Transitionen

Mit den vorgestellten Animationen können Sie das Aussehen eines oder mehrerer Views gleichzeitig ändern. Für das Memory-Spiel aus dem Beispielprojekt Games soll eine Animation das Umdrehen der Karten simulieren. Das können Sie mit Viewtransitionen erreichen.
Transitionen sind Animationen zum gleichzeitigen Ein- und Ausblenden von Views. Die Animation verbindet dabei das Erscheinen und das Verschwinden der Views zu einem Effekt. Es gibt folgende Transitionen:
| UIViewAnimationOptionTransition... | Die Animation ... |
|
...None |
Kein Animationseffekt. Das ist der |
|
...FlipFromLeft |
dreht die Views um deren vertikale Achse um 180° – die linke Seite nach vorne und die rechte nach hinten. |
|
...FlipFromRight |
dreht die Views um deren vertikale Achse um 180° – die rechte Seite nach vorne und die linke nach hinten. |
|
...FlipFromTop |
dreht die Views um deren horizontale Achse um 180°; dabei bewegt sich die obere Kante nach vorne und die untere nach hinten (erst ab iOS 5.0). |
|
...FlipFromBottom |
dreht die Views um deren horizontale Achse um 180°; dabei bewegt sich die obere Kante nach vorne und die untere nach hinten (erst ab iOS 5.0). |
|
...CurlUp |
blättert den auszublendenden View wie ein Kalenderblatt nach oben weg. |
|
...CurlDown |
blättert den einzublendenden View von oben ein. |
|
...CrossDissolve |
blendet den alten View aus und den neuen View durch einen Überblendeffekt ein (erst ab iOS 5). |
Sie können eine Transition über die Klassenmethode transitionWithView:duration:options:animations:completion: von UIView starten. Dabei geben Sie im ersten Parameter den View an, dessen Subviews Sie in die Transition einbeziehen möchten. Die Transition animiert alle Views, die Sie anzeigen, verstecken, zum View hinzufügen oder aus ihm entfernen. Die anderen Parameter verhalten sich genau wie bei den bereits vorgestellten Animationsmethoden.
Die Flipanimationen eignen sich hervorragend, um das Umdrehen der Karten im Memory-Spiel der Beispielapplikation zu animieren. Eine Karte im Memory besteht aus drei Views. Der äußere View der Klasse CardView dient als Container, der jeweils einen View für die Vorder- und Rückseite der Karte enthält. Die Vorderseite zeigt ein farbiges Vieleck, während die Rückseite ein einheitliches Punktmuster anzeigt. Von diesen beiden Views ist pro Karte allerdings immer nur einer sichtbar. Das Umdrehen einer Karte vertauscht einfach die Sichtbarkeit der beiden Karten; dabei steuern Sie die Transitionen der Karten über die Methode showFrontSide:withAnimationCompletion:.
- (FrontView *)frontView {
return self.subviews.lastObject;
}
- (BOOL)showsFrontSide {
return !self.frontView.hidden;
}
- (void)setShowsFrontSide:(BOOL)inShowFront {
[[self.subviews objectAtIndex:0] setHidden:inShowFront];
self.frontView.hidden = !inShowingFront;
}
- (void)showFrontSide:(BOOL)inShow withAnimationCompletion: 
(void (^)(BOOL inFinished))inCompletion {
UIViewAnimationOptions theTransition = inShow ? 
UIViewAnimationOptionTransitionFlipFromLeft : 
UIViewAnimationOptionTransitionFlipFromRight;
[UIView transitionWithView:self 
duration:0.75 options:theTransition | 
UIViewAnimationOptionAllowUserInteraction
animations:^{
self.showsFrontSide = inShow;
}
completion:inCompletion];
}
Listing 6.27 Umdrehen der Memory-Karten über eine Transsition
Der Animationsblock verändert die Property hidden der beiden Seiten der Karte, sodass sie jeweils nur einen View zeigt. Die Transition erzeugt daraus eine Animation, die wie ein Umdrehen der Karten aussieht. Für das Anzeigen und Verstecken der Vorderseite verwendet die Methode dabei die entgegengesetzten Transitionen.
Animierbare Properties
In Listing 6.27 sieht es so aus, als hätte die Klasse CardView mit der Property showsFrontSide eine neue animierbare Property. Tatsächlich ändert die Methode setShowsFrontSide: jedoch nur die Property hidden der Views.
Diese Property ist zwar auch nicht für gewöhnliche Animationen vorgesehen, Transitionen lassen sich allerdings darüber auslösen.
Über Core Animation können Sie auch animierbare Propertys in Ihren Viewklassen implementieren.
Wenn Sie in einer Transition auch noch Views animieren wollen, können Sie dazu die Option UIViewAnimationOptionAllowAnimatedContent setzen. Dann setzt Cocoa Touch alle Änderungen an Views im Animationsblock der Transition auch in Animationen um.
6.2.3 Zur Animation? Bitte jeder nur einen Block!
Wenn Sie mehrere Animationen hintereinander ausführen wollen, reicht dafür das Hintereinanderschreiben mehrerer Animationsanweisungen nicht aus. Die Animationen laufen dann trotzdem gleichzeitig ab. Das liegt einerseits daran, dass Cocoa Touch die Animationen auch aus der Runloop heraus startet. Andererseits warten die Animationsmethoden auch nicht auf den Ablauf der Animationen.
Bei Animationen können Sie dafür allerdings den Parameter delay verwenden. Wenn Sie ihn bei der zweiten Animation auf die Dauer der ersten Animation setzen, startet die zweite nach dem Ende der ersten.
Listing 6.28 enthält dazu ein Beispiel für drei aufeinanderfolgende Animationen. Es startet die erste ohne Verzögerung mit einer Dauer von einer Dreiviertelsekunde. Entsprechend startet der Code die zweite Animation mit einer Verzögerung von 750 Millisekunden. Die dritte Animation bekommt hingegen eine Verzögerung von 1250 Millisekunden, die sich aus der Summe der Dauern der ersten beiden Animationen errechnet.
[UIView animateWithDuration:0.75 animations:^{
// erste Animationsphase konfigurieren
}];
[UIView animateWithDuration:0.5 delay:0.75 options:0 
animations:^{
// zweite Animationsphase konfigurieren
}
completions:NULL];
[UIView animateWithDuration:0.25 delay:1.25 options:0 
animations:^{
// dritte Animationsphase konfigurieren
}
completions:NULL];
Listing 6.28 Starten von aufeinanderfolgenden Animationen
Bei Transitionen können Sie keine Verzögerung angeben. Hier können Sie jedoch den Completionblock nutzen. In diesem Block können Sie jeweils die anschließende Transition starten, sodass Sie auch hier eine sequenzielle Ausführung der Transitionen erhalten.
Das Memory-Spiel des Beispielprojekts besitzt einen Hilfeknopf, mit dem Sie die verdeckten Karten der Reihe nach kurz aufdecken können. Dazu besitzt die Klasse MemoryViewController die rekursive Methode showCardView:atIndex:, die den Inhalt der verdeckten Karten nacheinander kurz anzeigt.
- (void)showCardView:(BOOL)inShow atIndex:(NSUInteger)inIndex {
NSArray *theViews = self.memoryView.subviews;
UIViewAnimationOptions theOptions = inShow ?
UIViewAnimationOptionTransitionCurlUp :
UIViewAnimationOptionTransitionCurlDown;
if(inIndex < theViews.count) {
Card *theCard =
[self.memory.cards objectAtIndex:inIndex];
CardView *theView = [theViews objectAtIndex:inIndex];
[UIView transitionWithView:theView duration:0.25
options:theOptions
animations:^{
theView.showsFrontSide =
inShow || theCard.showsFrontSide;
}
completion:^(BOOL inFinished) {
[self showCardView:inShow atIndex:inIndex + 1];
if(inIndex == 0 && inShow) {
[self showCardView:NO atIndex:0];
}
}];
}
}
Listing 6.29 Animierte Hilfe des Memory-Spiels
Der erste Parameter gibt an, ob die Methode die Karte an der Indexposition zeigen oder verdecken soll. Das Auf- und Zudecken der Karte geschieht dabei auch über die Property showsFrontSide und eine CurlUp- beziehungsweise CurlDown-Transition. Der Completionblock der Transition startet dabei jeweils die Transition der nächsten Karte, sodass dadurch eine Kette von Transitionen entsteht. Außerdem startet der Completionblock für die erste Karte noch eine zweite Transitionskette zum Verdecken der Karten. Dazu verwendet er ebenfalls die Methode showCardView:atIndex:, diesmal allerdings mit dem Wert NO für den ersten Parameter, um die Karten zu verdecken.
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.





Jetzt bestellen





