6.2Als 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. Diese Methode verwendet dazu die Core-Graphics-Funktion CGImageCreateWithImageInRect, die genau diese Aufgabe erledigt.
Allerdings enthält ein Bild der Klasse UIImage seine Größe als geräteunabhängige Werte. Im Beispielprojekt ist das Puzzlebild 300 × 300 Punkte groß – egal, ob es für die Standard- oder die Retina-Auflösung ist. Koordinatenangaben in Core Graphics sind hingegen immer in Pixeln. Sie müssen also die logische Bildgröße erst in die physikalische umrechnen, indem Sie die Breite und die Höhe mit dem Skalierungsfaktor des Bildes multiplizieren. Diesen Faktor erhalten Sie über die Property scale der Klasse UIImage.
- (UIImage *)subimageWithRect:(CGRect)inRect {
CGFloat theScale = self.scale;
CGRect theRect = CGRectMake(
theScale * CGRectGetMinX(inRect),
theScale * CGRectGetMinY(inRect),
theScale * CGRectGetWidth(inRect),
theScale * CGRectGetHeight(inRect));
CGImageRef theImage = CGImageCreateWithImageInRect(
self.CGImage, theRect);
UIImage *theResult = [UIImage imageWithCGImage:theImage
scale:theScale orientation:UIImageOrientationUp];
CGImageRelease(theImage);
return theResult;
}
Listing 6.24 Kopieren eines rechteckigen Bereiches in ein neues Bild
Die zweite Methode, splitIntoSubimagesWithRows:columns:, der Kategorie zerlegt ein Bild auf Basis der Methode subimageWithRect: in gleich große, rechteckige Bilder und liefert das Ergebnis in einem Array zurück.
- (NSArray *)splitIntoSubimagesWithRows:(NSUInteger)inRows
columns:(NSUInteger)inColumns {
CGSize theSize = self.size;
CGRect theRect = CGRectMake(0.0, 0.0,
theSize.width / inColumns, 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.25 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.26 Aktualisierung der Puzzleteile
6.2.1Animationen mit Blöcken

Mit Hilfe 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 Touch für Sie. Diese Animationsbeschreibung erfolgt innerhalb eines Blocks. Die Arbeit mit Blöcken haben Sie ja bereits in Kapitel 2, »Die Reise nach iOS«, kennengelernt. Im einfachsten Fall wollen Sie nur eine oder mehrere Eigenschaften Ihrer Views verändern und das über eine Animation visualisieren. Beispielsweise vergrößern Sie folgendermaßen einen View animiert:
CGRect theFrame = theView.frame;
theFrame.size.width *= 2;
theFrame.size.height *= 2;
[UIView animateWithDuration:0.75 animations:^{
theView.frame = theFrame;
}];
Listing 6.27 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.27 können Sie deshalb die Definition des Animationsblocks von ^(void){ ... } auf ^{ ... } verkürzen.
Dieses Beispiel funktioniert allerdings nur bei ausgeschaltetem Autolayout. Mit eingeschaltetem Autolayout müssen Sie stattdessen die Restriktionen aktualisieren und im Animationsblock die Methode layoutIfNeeded des Views aufrufen. Dazu können Sie entweder die Restriktionen austauschen oder aktualisieren.
NSLayoutConstraint *theWidthConstraint = ...;
NSLayoutConstraint *theHeightConstraint = ...;
theWidthConstraint.constant *= 2.0;
theHeightConstraint.constant *= 2.0;
[UIView animateWithDuration:0.75 animations:^{
[theView layoutIfNeeded];
}
Listing 6.28 Animation über Autolayout-Restriktionen
Sie können also eine Animation durch einen Methodenaufruf und eine Zeile im Animationsblock starten. Cocoa Touch erzeugt automatisch die notwendigen Animationen zu den Änderungen, die Sie im Animationsblock an den Views vornehmen.
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.29 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 nach der Animation 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 verändern Sie die Position und die Größe 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.
- Ü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.
- Ein- und Ausblendeffekte erreichen Sie durch eine Änderung des Wertes der Property alpha.
- Sogar die Hintergrundfarbe des Views können Sie über die Property backgroundColor animieren.
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.
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 wir in Abschnitt 6.3, »Core Animation«, noch genauer eingehen.
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.30 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.30 Verknüpfung von zwei Transformationen
Während der Animationsausführung ist die Verarbeitung von Touch-Events der animierten Views unterbrochen, so dass 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 options-Parameters 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 Touch-Verarbeitung während der Animation lässt sich über die Konstante UIViewAnimationOptionAllowUserInteraction aktivieren.
Über View-Animationen können Sie Ihre Views auch kontinuierlich animieren, indem Sie den Schalter UIViewAnimationOptionRepeat setzen; dann setzt die Animation am Ende der Bewegung den View wieder auf den Ursprungszustand zurück und beginnt von vorn. 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 options-Parameter 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/iOS6/Animation oder im Github-Repository zum Buch im Unterverzeichnis https://github.com/Cocoaneheads/iPhone/tree/Auflage_3/Apps/iOS6/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. [Anm.: 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.31:
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.31 Wackelanimation wie beim Bearbeiten des Springboards
Animationen ohne Blockfunktionen
Viele Programmbeispiele im Netz starten Animationen über Aufrufe der Klassenmethoden beginAnimations:context: und commitAnimations und verwenden weitere Klassenmethoden zwischen diesen Aufrufen, um Animationsoptionen zu setzen. Die Animation aus Listing 6.27 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];
Apple hat dieses Verfahren der Animationserzeugung allerdings schon vor geraumer Zeit als veraltet markiert, und Sie sollten lieber die Klassenmethoden mit den Blockfunktionen verwenden.
6.2.2Transitionen

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 |
wird nicht beeinflusst, kein Animationseffekt. Das ist der Standardwert. |
...FlipFromLeft |
dreht die Views um deren vertikale Achse um 180° – die linke Seite nach vorn und die rechte nach hinten. |
...FlipFromRight |
dreht die Views um deren vertikale Achse um 180° – die rechte Seite nach vorn und die linke nach hinten. |
...FlipFromTop |
dreht die Views um deren horizontale Achse um 180°; dabei bewegt sich die obere Kante nach vorn und die untere nach hinten. |
...FlipFromBottom |
dreht die Views um deren horizontale Achse um 180°; dabei bewegt sich die obere Kante nach vorn und die untere nach hinten. |
...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. |
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.32 Umdrehen der Memory-Karten über eine Transition
Der Animationsblock verändert die Property hidden der beiden Seiten der Karte, so dass 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 Propertys
In Listing 6.32 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.3Zur 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.33 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 1.250 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.33 Starten von aufeinanderfolgenden Animationen
Bei Transitionen können Sie keine Verzögerung angeben. Hier können Sie jedoch den Completion-Block nutzen. In diesem Block können Sie jeweils die anschließende Transition starten, so dass 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.34 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 Curl-up- beziehungsweise Curl-down-Transition. Der Completion-Block der Transition startet dabei jeweils die Transition der nächsten Karte, so dass dadurch eine Kette von Transitionen entsteht. Außerdem startet der Completion-Block für die erste Karte 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.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.