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

Inhaltsverzeichnis
Geleitwort des Gutachters
Vorwort
1 Einführung
2 Einstieg in die Praxis
3 Aufwachen – analoger Wecker
4 Daten, Tabellen und Controller
5 Animationen und Layer
6 Programmieren, aber sicher
7 Jahrmarkt der Nützlichkeiten
A Die Buch-DVD
Stichwort

Download:
- ZIP, ca. 23,6 MB
Buch bestellen
Ihre Meinung?

Spacer
Apps entwickeln für iPhone und iPad von Klaus M. Rodewig, Clemens Wagner
Das Praxisbuch
Buch: Apps entwickeln für iPhone und iPad

Apps entwickeln für iPhone und iPad
geb., mit DVD
515 S., 34,90 Euro
Galileo Computing
ISBN 978-3-8362-1463-6
Pfeil 5 Animationen und Layer
Pfeil 5.1 Modell und Controller
Pfeil 5.1.1 iOS Next Topmodel
Pfeil 5.1.2 View an Controller
Pfeil 5.1.3 Modell an Controller
Pfeil 5.1.4 Undo und Redo
Pfeil 5.1.5 Unittests
Pfeil 5.2 Als die Views das Laufen lernten
Pfeil 5.2.1 Blockfunktionen in C
Pfeil 5.2.2 Animationen mit Blöcken
Pfeil 5.2.3 Transitionen
Pfeil 5.2.4 Zur Animation? Bitte jeder nur einen Block!
Pfeil 5.3 Core Animation
Pfeil 5.3.1 Layer
Pfeil 5.3.2 Vordefinierte Layerklassen
Pfeil 5.3.3 Unser Button soll schöner werden
Pfeil 5.3.4 Spieglein, Spieglein an der Wand
Pfeil 5.3.5 Der bewegte Layer
Pfeil 5.3.6 Der View, der Layer, seine Animation und ihr Liebhaber
Pfeil 5.3.7 Die 3. Dimension
Pfeil 5.4 Der Tabbar-Controller
Pfeil 5.4.1 Aufbau einer Reiternavigation
Pfeil 5.4.2 Für ein paar Controller mehr
Pfeil 5.5 Was Sie schon immer über Instruments wissen wollten, aber nie zu fragen wagten
Pfeil 5.5.1 Spiel mir das Lied vom Leak
Pfeil 5.5.2 Ich folgte einem Zombie
Pfeil 5.5.3 Time Bandits

Galileo Computing - Zum Seitenanfang

5.2 Als 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. 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 5.17 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.

- (NSArray *)splitIntoSubimagesWithRows:(NSUInteger)inRows
columns:(NSUInteger)inColumns {
CGSize theSize = self.size;
CGRect theRect = CGRectMake(0.0, 0.0,
self.size * theSize.width / inColumns,
self.size * 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] autorelease];
}

Listing 5.18 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 Subviewarray 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 5.19 Aktualisierung der Puzzleteile

Die Klasse UIView stellt eine Reihe von Methoden zur Verfügung, mit denen Sie Views animieren 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 oder auch einer Blockfunktion. Das ist eine Erweiterung der Programmiersprache C von Apple, die Xcode seit der Betriebssystemversion 10.6 (Snow Leopard) unterstützt. Das zugrunde liegende Konzept für Blöcke sind Closures aus den funktionalen Programmiersprachen wie beispielsweise LISP, Scheme oder Haskell. Vielleicht kennen Sie das Konzept aber auch schon aus anderen Programmiersprachen wie JavaScript, Ruby oder Python.


Galileo Computing - Zum Seitenanfang

5.2.1 Blockfunktionen in CZur nächsten ÜberschriftZur vorigen Überschrift

Ein Block ist eine Programmfunktion, die sich bei ihrer Erstellung Daten bis zu ihrer Ausführung merken kann. Sie können also einer Closure bei der Erzeugung schon Daten mitgeben, die sie bei ihrer späteren Ausführung verwendet.

Blockfunktionen

Dieser Abschnitt beschreibt Blöcke nur so weit, wie Sie sie für die Verwendung in Animationen brauchen. Falls Sie tiefer gehende Informationen dazu brauchen, sollten Sie in das Dokument Blocks Programming Topics schauen. Sie finden es in der API-Dokumentation oder unter folgender URL: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html

Dazu ein Beispiel: Ein Fischhändler verkauft tagein, tagaus auf dem Markt Makrelen. Die Kunden kommen zu ihm, um eine bestimmte Menge an Fisch zu kaufen. Dafür geben sie ihm einen entsprechenden Geldbetrag. Der Fischhändler braucht also eine Funktion, die einer Menge Fisch einen Geldbetrag zuordnet. Seine Makrelen bekommt der Fischhändler auf dem Großmarkt, wo die Kilopreise für Makrelen aber jeden Tag anders sind.

Der Fischhändler muss sich also jeden Morgen auf dem Markt neu überlegen, wie viel er für das Kilogramm Makrele von seinen Kunden haben will. Sie kennen ja das alte Marktwirtschaftsspielchen: Verlangt er zu viel, kauft keiner den Fisch. Ist der Fisch zu billig, dann geht er pleite. Da der gute Mann aber nicht jeden Tag ausführliche Marktforschungsanalysen betreiben möchte, hat die einfache Faustregel aufgestellt, den Fisch für den doppelten Einkaufspreis zu verkaufen. In die Verkaufsfunktion kommen also mit dem Einkaufspreis und dem Faktor noch zwei zusätzliche Werte ins Spiel.

Ohne Closures müssten Sie diese beiden Werte entweder als zusätzliche Funktionsparameter oder als globale Variablen umsetzen. Zusätzliche Funktionsparameter haben den Nachteil, dass Sie sie immer beim Funktionsaufruf verfügbar haben müssen. Globale Variablen schränken Ihre Funktion auf eine Variante ein. Wenn Sie beispielsweise mit einem Programm den Makrelenmarkt simulieren wollen, haben alle Fischverkäufer den gleichen Großmarktpreis bezahlt und berechnen den Verkaufspreis mit dem gleichen Faktor.

Mit Closures können Sie hingegen für jeden Fischverkäufer eine eigene Verkaufsfunktion erstellen. Das könnte dann so aussehen:

typedef double Money;
typedef double Weight;
Money thePurchasePrice = 4.20; // Einkaufspreis
double thePurchaseFactor = 2.0; // Aufschlagsfaktor
Money (^thePurchaseFunction)(Weight) = ^(Weight inWeight) {
return inWeight * thePurchasePrice * thePurchaseFactor;
};
Money thePrice = thePurchaseFunction(2.5); // = 21 Euro

Listing 5.20 Erzeugung einer Blockfunktion

Listing 5.20 erzeugt eine Blockfunktion, speichert sie in der Variablen thePurchaseFunction und ruft sie einmal mit dem Wert 2,5 auf. Für die Berechnung verwendet sie die Variablen thePurchasePrice und thePurchaseFactor, die außerhalb des Blocks definiert wurden. Dabei speichert das Laufzeitsystem diese Werte aber als Kontext der Blockfunktion ab. Wenn Sie die Werte der Variablen ändern, verändern Sie diese Werte in der Blockfunktion nicht. Wenn Sie also die Zeilen aus Listing 5.21 an Listing 5.20 anhängen, erhalten Sie den gleichen Verkaufspreis wie oben und nicht 18,90 Euro. Die Blockfunktion merkt sich also die Variablenwerte bis zu ihrer Ausführung.

thePurchaseFactor = 1.8;
thePrice = thePurchaseFunction(2.5); // = 21 Euro

Listing 5.21 Eine Änderung der Variablen ändert nicht die Blockfunktion.

Das ist bei Animationen wichtig, da Sie über einen Block beschreiben, wie der View nach der Animation aussehen soll. Wann Cocoa Touch diesen Block ausführt, kann Ihnen dabei egal sein. Er hat genau die Werte, die Sie bei seiner Erzeugung festgelegt haben.

Rückgabetyp von Blockfunktionen

Blockfunktionen sind sehr streng bezüglich ihres Rückgabetyps. Im Gegensatz zu vielen C-Anweisungen konvertieren sie den Wert nicht automatisch in den richtigen Typ. Das liegt daran, dass die Definition die Deklaration nicht kennt. Die Definition muss also den Rückgabetyp aus der Return-Anweisung extrahieren:

^(void) { return 1; } // Rückgabetyp int
^(void) { return 1.0; } // Rückgabetyp double
^(void) { return 1.0f; } // Rückgabetyp float
Sie müssen also sicherstellen, dass die Rückgabetypen der Blockdeklaration und ?definition übereinstimmen. Das gilt übrigens auch, wenn der Block ein Objekt zurückgeben soll. Auch hier wandelt der Compiler nicht automatisch in die Oberklasse um:
id ^(theBlock)(void) = ^(void) { return @"Hello"; }; // Fehler
NSObject *^(theBlock)(void) { return @"Hello"; }; // Fehler
Sie müssen hier explizit in den richtigen Rückgabetyp umwandeln:
id ^(theBlock)(void) = ^(void) { return (id)@"Hello"; }; // OK
Wenn Sie Blockfunktionen in Ihren Programmen verwenden möchten, sollten Sie wie in Listing 5.23 dafür über typedef eigene Typen definieren. Das vereinfacht Ihnen die Deklaration von Variablen.

Sie können diese Funktion nicht nur aufrufen, sondern auch wie ein Objekt behandeln. Beispielsweise können Sie die Funktion als Parameterwert an eine andere Funktion oder eine Methode übergeben. Dabei ist es wichtig, dass Sie die Blockfunktion nur innerhalb des Bereiches verwenden dürfen, in dem Sie sie deklariert haben. Folgendes dürfen Sie beispielsweise nicht machen:

if(YES) { /* Anfang */
thePurchaseFunction = ^(Weight inWeight) {
return inWeight * thePurchasePrice * 2.1;
};
/* Ende */ }
thePrice = thePurchaseFuntion(3.1); // Fehler

Listing 5.22 Bereichsverletzungen mit Blöcken

Die letzte Anweisung in Listing 5.22 ist eine Bereichsverletzung, weil sie die Blockfunktion außerhalb des deklarierenden Bereichs verwendet (der durch /* Anfang */ und /* Ende */ gekennzeichnet ist). Sie dürfen eine Blockfunktion auch nicht einfach als Funktions- oder Methodenergebnis zurückgeben, da Sie auch hier den deklarierenden Block verlassen. Bei Bereichsverletzungen von Blöcken gibt Ihnen der Compiler in vielen Fällen keine Fehlermeldungen aus. Es kann sogar vorkommen, dass das Programm trotz einer Bereichsverletzung funktioniert.

Sie können Bereichsverletzungen vermeiden, indem Sie den Block kopieren. Hier treten die Objekteigenschaften von Blöcken zutage. Sie können nämlich auch an Blöcke die Methoden retain, release, autorelease und copy senden. Wenn Sie also einen Block aus einer Methode zurückgeben möchten, schicken Sie ihm ein copy und gegebenenfalls noch ein autorelease (erinnern Sie sich noch an die erste Speicherverwaltungsregel?):

typedef double (^FunctionType)(double inValue);
- (FunctionType)createFunction {
return [[^(double inValue) {...} copy] autorelease];
}
- (double)evaluateFunctionWithValue:(double)inValue {
FunctionType theFunction = [self createFunction];
return theFunction(inValue);
}

Listing 5.23 Das Kopieren von Blöcken

Blockfunktionen und ARC

Automatisches Referenzenzählen (ARC) vereinfacht die Handhabung von Blockfunktionen als Rückgabewerte. Sie können hier beispielsweise einfach

return ^(void){ ... };
schreiben. Der ARC-Compiler fügt automatisch die notwendigen Aufrufe von copy und autorelease ein:
return [[^(void){ ... } copy] autorelease];

Wenn Sie Blockfunktionen in Objekten speichern möchten, ist es am einfachsten, dafür Propertys vom Typ copy zu verwenden. Sie können dann die Propertywerte wie bei anderen Propertys auch zuweisen. Durch den Speicherverwaltungstyp kopiert die Laufzeitumgebung automatisch die Blockfunktion bei der Zuweisung:

// Typdeklaration
typedef double (^FunctionType)(double inValue);
// Propertydeklaration
@property(nonatomic, copy) FunctionType function;
// Zuweisung
self.function = ^(double inValue) { ... };
// Ausführung
self.function(2.5);

Listing 5.24 Blockfunktion als Propertywert


Galileo Computing - Zum Seitenanfang

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

Mit diesen Grundlagen für Blöcke können Sie jetzt anfangen, Ihre Views in Bewegung zu setzen. Dazu bietet Ihnen die Klasse UIView eine Reihe von Klassenmethoden. Die Methoden sind nicht auf Objektebene, da Sie innerhalb einer Animation mehrere Views gleichzeitig verändern können. 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 5.25 Animierte Vergrößerung eines Views

Parameterlose Blockfunktionen

Wenn eine Blockfunktion keinen Parameter erwartet, können Sie die Angabe der Parameterliste auch weglassen. In Listing 5.25 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 zu den Änderungen, die Sie im Animationsblock an den Views vornehmen, die notwendigen Animationen. In vielen Fällen möchten Sie am Ende der Animation weiteren Code ausführen. Dafür gibt es eine Variante mit zwei Blockfunktionen:

[UIView animateWithDuration:0.75 animations:^{
theView.frame = theFrame;
}
completion:^(BOOL inFinished) {
theView.alpha = 0.5;
}];

Listing 5.26 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 Beendigung abgebrochen hat. In der Regel hat dieser Parameter also den Wert YES.

Abbrechen von Animationen

Für den Abbruch von View-Animationen gibt es keine dokumentierte Methode im UIKit. Da diese Animationen aber auf Core Animation basieren, können Sie auf die Animationen eines Views über seinen Layer zugreifen. Über die folgende Anweisung können Sie alle Animationen stoppen:

[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 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 5.10). 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. Dadurch sind die Größenangaben unabhängig von der Größe des Views. Das Rechteck für Abbildung 5.10 hat beispielsweise folgende Werte:

theView.contentStretch = CGRectMake(0.125, 0.25, 0.625, 0.5);

Abbildung

Abbildung 5.10 Dehnbare Bereiche (Pfeile) eines Views

Während der Animationsausführung ist die Verarbeitung von Touch-Events unterbrochen, sodass Sie also keine Eingaben empfangen können. In vielen Fällen ist das auch nicht notwendig. Es gibt aber noch eine dritte Animationsmethode, 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 die Ausführung der Animation verzögern.

Der Wert des Optionsparameters ist eine Bitmenge, die Sie aus mehreren Konstanten, die einen booleschen Wert darstellen, zusammensetzen können. Wenn Sie mehrere Eigenschaften über die Optionen setzen wollen, müssen Sie die entsprechenden Konstanten über das bitweise Oder (Operator |) verknüpfen.

Sie können die Touchverarbeitung während der Animation über die Konstante UIViewAnimationOptionAllowUserInteraction einschalten. Über Viewanimationen können Sie Ihre Views aber auch kontinuierlich animieren. Dazu brauchen Sie nur den Schalter UIViewAnimationOptionRepeat zu setzen, dann setzt die Animation am Ende der Bewegung den View wieder auf den Ursprungszustand zurück und beginnt von vorne. Der Parameter duration gibt bei wiederholten Animationen die Länge einer Wiederholung an, und die gesamte Animation läuft dauerhaft. 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 5.3 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.

Das Beispielprogramm Animation auf der beiliegenden DVD vermittelt einen Eindruck von den verschiedenen Animationsverläufen. Sie können dort über ein Segmented Control die Animationskurve wählen und eine Animation starten.

Animationen ohne Blockfunktionen

Blockfunktionen hat Apple erst mit iOS 4.0 eingeführt. Trotzdem können Sie auch in älteren iOS-Versionen Animationen einbinden (Sie sollten aber möglichst die Blockfunktionen bevorzugen).

Zum Einbinden in älteren iOS-Versionen müssen Sie Ihre Animationen in 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 5.25 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 der nächste Abschnitt noch genauer ein. Im Context-Parameter können Sie der Animation beliebige Daten mitgeben, die sie an Ihre Delegatemethoden weitergibt.


Galileo Computing - Zum Seitenanfang

5.2.3 TransitionenZur 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 des Beispielprogramms dieses Kapitels sollte die Animation das Umdrehen der Karten simulieren. Das können Sie mit View-Transitionen 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 5.4 Transitionstypen

UIViewAnimationOptionTransition... Die Animation ...
...None Kein Animationseffekt. Das ist der Standardwert.
...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.
...CurlUp blättert den auszublendenden View wie ein Kalenderblatt nach oben weg.
...CurlDown blättert den einzublendenden View von oben 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 herragend, um das Umdrehen der Karten im Memoryspiel 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 Muster anzeigt. Der Containerview steuert die Transitionen der Karte über die Methode showFrontSide:withAnimationCompletion:.

- (FrontView *)frontView {
return self.subviews.lastObject;
}
- (BOOL)showsFrontSide {
return !self.frontView.hidden;
}
- (void)setShowsFrontSide:(BOOL)inShowingFront {
[[self.subviews objectAtIndex:0] setHidden:inShowingFront];
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 5.27 Transition der Memorykarten

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.

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.


Galileo Computing - Zum Seitenanfang

5.2.4 Zur 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. Dafür gibt es ja schließlich den Completionblock. In diesem Block können Sie die anschließende Animation starten, sodass Sie eine sequenzielle Ausführung der Animationen 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 die Karten nacheinander kurz aufdeckt.

- (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 5.28 Animierte Hilfe des Memoryspiels

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, sodass dadurch eine Kette von Animationen entsteht. Der Completion-Block für die erste Karte startet außerdem noch eine zweite Animationskette zum Verdecken der Karten.



Ihr Kommentar

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







<< zurück
  Zum Katalog
Zum Katalog: Apps entwickeln für iPhone und iPad





Apps entwickeln für iPhone und iPad
Jetzt bestellen


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

 Buchempfehlungen
Objective-C 2.0 & Cocoa





 Objective-C 2.0
 Cocoa


Zum Katalog: Mac OS X Lion






 Mac OS X Lion


Zum Katalog: Mac OS X und UNIX






 Mac OS X
 und UNIX


Zum Katalog: Android 3






 Android 3


Zum Katalog: Java ist auch eine Insel






 Java ist auch
 eine Insel


Zum Katalog: CSS






 CSS


Zum Katalog: jQuery






 jQuery


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2011
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.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de