Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort
Vorwort
1 Hello iPhone
2 Die Reise nach iOS
3 Sehen und anfassen
4 Alles unter Kontrolle
5 Daten, Tabellen und Controller
6 Models, Layer, Animationen
7 Programmieren, aber sicher
8 Datenserialisierung und Internetzugriff
9 Multimedia
10 Jahrmarkt der Nützlichkeiten
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
Apps programmieren für iPhone und iPad von Klaus M. Rodewig, Clemens Wagner
Das umfassende Handbuch
Buch: Apps programmieren für iPhone und iPad

Apps programmieren für iPhone und iPad
Rheinwerk Computing
1172 S., geb., mit DVD
49,90 Euro, ISBN 978-3-8362-2734-6
Pfeil 6 Models, Layer, Animationen
Pfeil 6.1 Modell und Controller
Pfeil 6.1.1 iOS Next Topmodel
Pfeil 6.1.2 View an Controller
Pfeil 6.1.3 Gerätebewegungen auswerten
Pfeil 6.1.4 Modell an Controller
Pfeil 6.1.5 Undo und Redo
Pfeil 6.1.6 Unit-Tests
Pfeil 6.2 Als die Views das Laufen lernten
Pfeil 6.2.1 Animationen mit Blöcken
Pfeil 6.2.2 Transitionen
Pfeil 6.2.3 Zur Animation? Bitte jeder nur einen Block!
Pfeil 6.3 Core Animation
Pfeil 6.3.1 Layer
Pfeil 6.3.2 Vordefinierte Layer-Klassen
Pfeil 6.3.3 Der Layer mit der Maske
Pfeil 6.3.4 Unser Button soll schöner werden
Pfeil 6.3.5 Spieglein, Spieglein an der Wand
Pfeil 6.3.6 Der bewegte Layer
Pfeil 6.3.7 Daumenkino
Pfeil 6.3.8 Relativitätstheorie
Pfeil 6.3.9 Der View, der Layer, seine Animation und ihr Liebhaber
Pfeil 6.3.10 Transaktionen
Pfeil 6.3.11 Die 3. Dimension
Pfeil 6.4 Scrollviews und gekachelte Layer
Pfeil 6.4.1 Scrollen und Zoomen
Pfeil 6.4.2 Die Eventverarbeitung
Pfeil 6.4.3 Scharfe Kurven
Pfeil 6.4.4 Ganz großes Kino
Pfeil 6.4.5 PDF-Dateien anzeigen
Pfeil 6.5 Über diese Brücke musst du gehen
Pfeil 6.5.1 Toll-free Bridging und ARC
Pfeil 6.5.2 C-Frameworks und ARC
Pfeil 6.6 Was Sie schon immer über Instruments wissen wollten, aber nie zu fragen wagten
Pfeil 6.6.1 Spiel mir das Lied vom Leak
Pfeil 6.6.2 Ich folgte einem Zombie
Pfeil 6.6.3 Time Bandits
Pfeil 6.6.4 Instruments und der Analyzer

Rheinwerk Computing - Zum Seitenanfang

6.2Als die Views das Laufen lerntenZur nächsten Überschrift

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


Rheinwerk Computing - Zum Seitenanfang

6.2.1Animationen mit BlöckenZur nächsten ÜberschriftZur vorigen Überschrift

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:

  1. Mit den Propertys frame und bounds verändern Sie die Position und die Größe des Views.
  2. 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.
  3. Ü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.
  4. Ein- und Ausblendeffekte erreichen Sie durch eine Änderung des Wertes der Property alpha.
  5. 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.

Tabelle 6.3 Erzeugung von Transformationsmatrizen

Funktion Beschreibung

CGAffineTransformMake

Erzeugt eine Transformationsmatrix über sechs Werte: eine 2×2-Matrix und eine Verschiebung. Diese Funktion verwendet man aber nur äußerst selten.

CGAffineTransformMakeRotation

Über diese Funktion erstellen Sie eine Drehung zu einem angegebenen Winkel im Bogenmaß.

CGAffineTransformMakeScale

Erstellt eine Skalierung über zwei Werte entlang der x- und der y-Achse. Mit den Wertpaaren (1, -1) und (-1, 1) können Sie den View an der x- beziehungsweise y-Achse spiegeln.

CGAffineTransformMakeTranslation

Diese Transformation verschiebt den View in Richtung der angegebenen Werte.

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:

Tabelle 6.4 Geschwindigkeitsverläufe in der Animation

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.


Rheinwerk Computing - Zum Seitenanfang

6.2.2TransitionenZur nächsten ÜberschriftZur vorigen Überschrift

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:

Tabelle 6.5 Transitionstypen

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.


Rheinwerk Computing - Zum Seitenanfang

6.2.3Zur Animation? Bitte jeder nur einen Block!Zur vorigen Überschrift

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.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück




Copyright © Rheinwerk Verlag GmbH, Bonn 2014
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de


  Zum Katalog
Zum Katalog: Apps programmieren für iPhone und iPad






Neuauflage: Apps programmieren für iPhone und iPad
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Einstieg in Objective-C 2.0 und Cocoa






Einstieg in Objective-C 2.0 und Cocoa


Zum Katalog: Spieleprogrammierung mit Android Studio






Spieleprogrammierung mit Android Studio


Zum Katalog: Android 5






Android 5


Zum Katalog: iPhone und iPad-Apps entwickeln






iPhone und iPad-Apps entwickeln


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo