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.3 Core AnimationZur nächsten Überschrift

Auf den ersten Blick wirken die View-Animationen ein bisschen wie Magie. Durch einen zusätzlichen Methodenaufruf verwandeln Sie eine statische Veränderung des Views in einen eleganten Übergang, wobei Sie auch noch eine große Palette möglicher Animationen haben. Da fragt sich doch der neugierige Programmierer, wie das funktioniert. Die Antwort darauf ist relativ einfach. Dazu müssen Sie aber eine Ebene tiefer gehen.

Core Animation ist eine Sammlung von Klassen zur Darstellung, Projektion und Animation von Grafiken. Der Name Core Animation ist vielleicht etwas verwirrend, da Sie Core Animation auch ohne Animationen sinnvoll verwenden können.

Core Animation verwenden

Wenn Sie die Klassen aus Core Animation in Ihren Apps verwenden möchten, müssen Sie das QuartzCore-Framework einbinden. Außerdem müssen Sie den entsprechenden Header über

#import <QuartzCore/QuartzCore.h>
in Ihre Quelldateien importieren, damit der Compiler Ihren Programmcode übersetzen kann.


Galileo Computing - Zum Seitenanfang

5.3.1 LayerZur nächsten ÜberschriftZur vorigen Überschrift

Die Views des UIKits verwenden Core-Animation-Layer für ihre Darstellung. Ein Layer ist eine Zeichenebene, die Inhalte für die Anzeige bereitstellt. Die Basisklasse für alle Layer ist CALayer. Dabei ist jedem View ein Layer zugeordnet, den Sie über die Property layer erhalten. Nach der Erzeugung eines Views ist dessen Layer fest, und Sie können dem View keinen neuen Layer zuweisen. Die Klasse UIView hat aber die Klassenmethode layerClass, über die der View die Klasse seines Layers bestimmt. Sie können in Ihren Unterklassen also diese Methode implementieren, um so die Layerklasse des Views festlegen zu können.

+ (Class)layerClass {
return [PieLayer class];
}

Listing 5.29 Festlegen der Layerklasse eines Views

Layer können, analog zu Views, Sublayer haben. Wenn ein View Subviews hat, dann sind deren Layer die Sublayer des Layers des Views. Eine grafische Veranschaulichung des letzten Satzes finden Sie in Abbildung 5.11.

Jedem View ist zwar ein Layer zugeordnet, aber nicht jeder Layer muss zu einem View gehören. Sie können also in einen Layer beliebig viele Sublayer einfügen. Die Verwaltung der Sublayer erfolgt dabei analog zu Views. Sie erhalten alle Sublayer eines Layers über die Property sublayers. Durch die Methode addSublayer: können Sie neue Sublayer zu einem Layer hinzufügen, und über die Property superlayer haben Sie Zugriff auf den darüber liegenden Layer.

Abbildung

Abbildung 5.11 View- und Layer-Hierarchie

Layer haben noch eine Reihe weiterer Eigenschaften. Sie finden im Layer viele Propertys, die Sie schon von der Klasse UIView kennen. Teilweise haben sie aber einen anderen Namen. Beispielsweise heißt clipsToBounds im Layer masksToBounds. Das Gegenstück zu der Viewproperty alpha ist opacity. Wenn sie den Wert 0 hat, ist der Layer transparent. Bei einem Wert von 1 ist er deckend.

Sehr praktisch ist beispielsweise die Property cornerRadius der Klasse CALayer. Damit können Sie die Ecken eines Layers abrunden. Dafür müssen Sie diese Property auf einen Wert größer als 0 setzen. Außerdem können Sie noch einen Schatten, eine Rahmenfarbe und eine Rahmenbreite festlegen:

theLayer.cornerRadius = 10.0;
theLayer.borderColor = [UIColor blueColor].CGColor;
theLayer.borderWidth = 2.0;
theLayer.shadowColor = [UIColor blackColor].CGColor;
theLayer.shadowOffset = CGSizeMake(5.0, 5.0);
theLayer.shadowOpacity = 0.5;

Listing 5.30 Erzeugung eines Layerrahmens

Wenn Sie die Propertys wie in Listing 5.30 setzen, erhalten Sie einen Rahmen um den Layer, wie er in Abbildung 5.12 dargestellt ist. Sie können diese Propertys natürlich auch bei dem Layer eines Views setzen, um die Ecken eines rechteckigen Views abzurunden. Das ist eine einfache Möglichkeit, um die Gestaltung der Oberflächen Ihrer Apps aufzulockern.

Ein Layer kann auch ein Delegate haben. Bei den Standardlayern der Views ist das Delegate immer der View. Sie dürfen diesen Layern kein anderes Delegate zuweisen. Bei allen anderen Layern können Sie hingegen das Delegateobjekt frei wählen und über die Property delegate setzen.

Diplomatischer Skandal: Layer-Delegation hält sich an kein Protokoll

Es gibt kein Protokoll für das Layer-Delegate. Die Delegatemethoden finden Sie alle in der Klasse CALayer. In deren Dokumentation sind alle Delegatemethoden durch den Zusatz delegate method gekennzeichnet.

Es gibt drei mögliche Wege, wie Sie den Inhalt eines Layers bereitstellen können. Über die Property contents können Sie dem Layer ein Core-Graphics-Bild (CGImageRef) zuweisen. Eine solche Referenz erhalten Sie beispielsweise über die Property CGImage eines Bildes des UIKits.

UIImage *theImage = [UIImage imageNamed:@"background.png"];
theLayer.contents = theImage.CGImage;

Listing 5.31 Setzen der »contents«-Property eines Layers

Der Layer-Inhalt lässt sich aber auch durch Zeichenoperationen erzeugen. Sie können dafür entweder eine Delegatemethode verwenden oder eine Unterklasse erstellen. Für die Delegation implementieren Sie die Methode drawLayer: inContext:, wobei Sie den Kontextparameter für Ihre Zeichenoperationen verwenden:

- (void)drawLayer:(CALayer *)inLayer
inContext:(CGContextRef)inContext {
CGContextSaveGState(inContext);
// beliebige Zeichenoperationen
CGContextRestoreGState(inContext);
}

Listing 5.32 Layer-Inhalt über Delegatemethode zeichnen

Cocoa Touch ruft die Methode drawRect: über drawLayer:inContext: auf. Sie haben also bereits – ohne es zu ahnen – Layer-Inhalte über Delegation erzeugt.

UIView und drawLayer:inContext:

Wenn Sie den View-Inhalt über die Delegatemethode anstatt mit drawRect: zeichnen möchten, dann müssen Sie trotzdem die Methode drawRect: überschreiben. Ansonsten ruft der Layer die Delegatemethode nicht auf. Es reicht aber aus, wenn Sie die Methode leer lassen.

Der dritte Weg zur Bereitstellung des Layer-Inhalts ist das Überschreiben der Methode drawInContext: in einer Unterklasse von CALayer. Auch hier bekommen Sie den Kontext zum Zeichnen als Parameter übergeben.

Abbildung

Abbildung 5.12 Das »Pie«-Beispielprogramm

Das Beispielprojekt Pie auf der beiliegenden DVD stellt ein Kreissegment dar, dessen Ausschnitt Sie über einen Schieberegler verändern können (siehe Abbildung 5.12). Die Darstellung des Segments basiert auf einem Layer mit folgender Implementierung der Methode drawInContext:

- (void)drawInContext:(CGContextRef)inContext {
CGRect theBounds = self.bounds;
CGSize theSize = theBounds.size;
CGFloat thePart = self.part;
CGPoint theCenter = CGPointMake(CGRectGetMidX(theBounds),
CGRectGetMidY(theBounds));
CGFloat theRadius = fminf(theSize.width, theSize.height) /
2.0 – 5.0;
CGFloat theAngle = 2 * (thePart – 0.25) * M_PI;

CGContextSaveGState(inContext);
CGContextSetFillColorWithColor(inContext, [UIColor redColor].CGColor);
CGContextMoveToPoint(inContext, theCenter.x, theCenter.y);
CGContextAddArc(inContext, theCenter.x, theCenter.y, theRadius, -M_PI / 2.0, theAngle, NO);
CGContextAddLineToPoint(inContext, theCenter.x, theCenter.y);
CGContextFillPath(inContext);
CGContextRestoreGState(inContext);
}

Listing 5.33 Zeichnen des Kreissegments im Layer

Die Property part enthält die Größe des Kreissegments als Wert zwischen 0 und 1. Ein Layer kann über die Methoden valueForKey: und setValue:forKey: beliebige Werte speichern. Die Klasse PieLayer speichert den Wert für die Property part auch über diese Methoden. Die Deklaration dieser Property in der Klasse PieLayer erfolgt zwar über ein gewohntes

@property (nonatomic) CGFloat part;

für die Implementierung reicht aber die Anweisung @dynamic part; aus. Dadurch ruft die Laufzeitumgebung immer, wenn Sie lesend oder schreibend auf part zugreifen, die Methoden valueForKey: beziehungsweise setValue:forKey: mit @"part" als Schlüssel auf, wobei sie den Fließkommawert auch immer schön aus einem NSNumber-Objekt auspackt beziehungsweise ihn in ein solches Objekt verpackt.

Layer-Eigenschaften über Propertys

Legen Sie die Propertys eines Layers möglichst immer dynamisch an. Sie können zwar auch synthetisierte Propertys verwenden oder eigene Implementierungen dafür schreiben. Allerdings dürfen Sie in der Implementierung nicht die Key-Value-Coding-Methoden mit dem Propertyname als Schlüssel verwenden. Die Implementierung

- (CGFloat)part {
return [[self valueForKey:@"part"] floatValue];
}
führt zu einer Endlosrekursion, da der Aufruf von valueForKey: wieder die Methode part aufruft. Sie bekommen aber weiteren Ärger, wenn Sie diese Propertys animieren wollen. Also nutzen Sie lieber das Key-Value-Coding. Das ist ein Angebot, das Sie einfach nicht ablehnen können.

Natürlich sollte der Layer seine Propertys auch mit Werten vorbelegen. Dafür sollten Sie die Klassenmethode defaultValueForKey: überschreiben. Sie liefert für die Schlüssel des Layers entweder den Standardwert zurück oder reicht den Aufruf an die Methode der Oberklasse weiter. Da diese Methode den Rückgabetyp id hat, muss sie den Standardwert für die Property part als Objekt liefern.

static NSString * const kPartKey = @"part";

+ (id)defaultValueForKey:(NSString *)inKey {
return [kPartKey isEqualToString:inKey] ?
[NSNumber numberWithFloat:0.0] : [super defaultValueForKey:inKey];
}

Listing 5.34 Standardwert für die Property »part«

Wenn Sie jetzt die Klasse PieLayer verwenden, sehen Sie noch nichts – zumindest kein Tortenstück. Das könnte daran liegen, dass die Größe des Segments den Wert Null hat. Aber selbst mit einem anderen Standardwert für part gibt’s immer noch keinen Kuchen und die Fläche bleibt immer noch weiß.

Das liegt daran, dass niemand dem Layer gesagt hat, dass er etwas zeichnen soll. Sie können das erreichen, indem sie ihm die Nachricht setNeedsDisplay schicken. Das müssen Sie immer machen, wenn Sie den Wert für part verändern. Das ist aber sehr unpraktisch, da Sie dafür entweder die Methode setPart: implementieren oder KVO verwenden müssten.

Um dieses Problem zu umgehen, bietet die Layerklasse über die Klassenmethode needsDisplayForKey: eine einfachere Möglichkeit an. Core Animation zeichnet den Layer bei einer Änderung eines Propertywertes automatisch neu, wenn die Methode für den Propertynamen YES liefert. Sie können dazu diese Methode in Ihren Klassen einfach überschreiben.

+ (BOOL)needsDisplayForKey:(NSString *)inKey {
return [kPartKey isEqualToString:inKey] || [super needsDisplayForKey:inKey];
}

Listing 5.35 Layer bei Änderung des Propertywertes neu zeichnen

Layer-Propertys gesucht

Core Animation ruft die Methode needsDisplayForKey: einmal für jede Property der Layerklasse auf. Sie sollten auch deshalb die Layereigenschaften als dynamische Property deklarieren. Für Eigenschaften, die Sie als Getter und Setter deklariert haben, ruft Core Animation needsDisplayForKey: nicht auf. Das klingt ja schon wieder nach einem Angebot, das Sie nicht ausschlagen können.


Galileo Computing - Zum Seitenanfang

5.3.2 Vordefinierte LayerklassenZur nächsten ÜberschriftZur vorigen Überschrift

Core Animation stellt fertige Unterklassen von CALayer für verschiedene Anwendungsfälle bereit. Den Programmcode zu den vier hier vorgestellten Layern finden Sie im Beispielprojekt Layer auf der beiliegenden DVD. Die Darstellung der Ausgabe der beschriebenen Layer ist in Abbildung 5.13 zu sehen.

Abbildung

Abbildung 5.13 Ausgabe der Layer-App

Mit einem Layer der Klasse CAGradientLayer können Sie Farbverläufe darstellen, die auf zwei oder mehr Farben basieren. Die Farben übergeben Sie an den Layer als CGColorRef-Werte in einem NSArray. Der Farbverlauf verläuft entlang einer Linie, die Sie über die Propertys startPoint und endPoint festlegen.

Abbildung

Abbildung 5.14 Gradientenverlauf zwischen Start- und Endpunkt

Relative Positionsangaben bei Layern

Positionen oder Rechtecke innerhalb eines Layers müssen Sie in der Regel durch Werte zwischen 0 und 1 beschreiben und nicht durch absolute Koordinaten. Den Ankerpunkt eines Layers können Sie beispielsweise über die Property anchorPoint festlegen. Standardmäßig ist das der Mittelpunkt des Layers, und diese Property hat also den Wert (0,5, 0,5).

Abbildung 5.14 enthält zwei Gradientenverläufe mit unterschiedlichen Start- und Endpunkten. Die Lage der Punkte verdeutlicht dabei jeweils eine Verbindungslinie auf dem Gradienten. Der linke Verlauf startet in der Ecke links oben und endet unten rechts. Der Startpunkt hat also den Wert (0, 0) und der Endpunkt (1, 1). Der rechte Gradient verläuft von oben nach unten, was sich über den Startpunkt (0,5, 0) und den Endpunkt (0,5, 1) realisieren lässt.

Über Layer der Klasse CATextLayer können Sie Texte darstellen. Die Implementierung des Layers beruht auf Core Text. Das ist ein Low-Level-Framework für die Ausgabe von Texten. Sie können im Gegensatz zu einem Label über diesen Layer auch Texte mit Hervorhebungen (z. B. fett oder kursiv) und unterschiedlichen Schriftarten ausgeben.

Die Klasse CAScrollLayer erlaubt die Anzeige von Inhalten, die größer sind als der verfügbare Bereich für die Darstellung. Sie zeigen also wie ein UIScrollView immer nur einen Ausschnitt des Inhalts an. Im Gegensatz zum View verarbeitet der Layer aber keine Gesten, und er zeigt auch keine Scrollbalken an.

Sie können den angezeigten Ausschnitt des Scrolllayers über die Methoden scrollToPoint: und scrollToRect: festlegen. Über scrollToPoint: legen Sie die linke obere Ecke des Ausschnitts für die Anzeige fest. Dabei geben Sie den Punkt in absoluten Koordinaten zum Layerinhalt an. Bei scrollToRect: übergeben Sie ein Rechteck aus dem Koordinatensystem des Inhalts. Der Scrolllayer stellt dann einen Ausschnitt des Inhalts dar, der dieses Rechteck enthält.

Ein Layer der Klasse CAShapeLayer stellt einen Core-Graphics-Pfad dar. Dabei können Sie diesen Pfad über die Property path setzen. Auch für die anderen üblichen Verdächtigen gibt es entsprechende Propertys. Sie können beispielsweise die Füllfarbe über fillColor und die Linienfarbe über strokeColor setzen.


Galileo Computing - Zum Seitenanfang

5.3.3 Unser Button soll schöner werdenZur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse GradientButton der Games-App verwendet einen Gradienten-Layer, um optisch ansprechende Buttons darzustellen. Dazu fügt sie in der Methode awakeFromNib einen weiteren Sublayer hinzu:

- (void)awakeFromNib {
[super awakeFromNib];
CALayer *theLayer = self.layer;
CAGradientLayer *theBackground = [CAGradientLayer layer];

theLayer.cornerRadius = 10.0;
theLayer.masksToBounds = YES;
theBackground.frame = theLayer.bounds;
theBackground.startPoint = CGPointMake(0.5, 0.2);
theBackground.endPoint = CGPointMake(0.5, 0.4);
theBackground.colors = self.normalColors;
theBackground.zPosition = –1;
[theLayer addSublayer:theBackground];
self.backgroundLayer = theBackground;
}

Listing 5.36 Hinzufügen eines Layers für den Hintergrund

Der Layer für den Hintergrund erhält die z-Position (siehe Abschnitt 5.3.7, »Die 3. Dimension«) –1, damit er hinter den anderen Elementen des Buttons liegt. Da der Button einen transparenten Hintergrund hat, verdeckt der Button aber nicht den Hintergrundlayer. Wenn Sie den Button drücken, verändert sich die Farbe des Verlaufs wie beim Redo-Button in Abbildung 5.15. Dazu besitzt die Klasse zwei Getter, die jeweils ein Array mit Farben liefern. Die Arrays müssen allerdings die Farbwerte als CGColorRef-Werte enthalten:

- (NSArray *)normalColors {
return [NSArray arrayWithObjects:
(id)[UIColor colorWithRed:0.0 green:0.0 blue:0.9
alpha:1.0].CGColor, [UIColor colorWithRed:0.0 green:0.0 blue:0.6 alpha:1.0].CGColor, nil];
}

- (NSArray *)highligthedColors {
return [NSArray arrayWithObjects:
(id)[UIColor colorWithRed:0.9 green:0.0 blue:0.0 alpha:1.0].CGColor,
[UIColor colorWithRed:0.6 green:0.0 blue:0.0 alpha:1.0].CGColor, nil];
}

Listing 5.37 Definition der Verlaufsfarben für den Hintergrund

Abbildung

Abbildung 5.15 Änderung der Hintergrundfarbe eines gedrückten Buttons

Damit der Button die Farbe beim Drücken verändert, überschreiben Sie die Methode setHighlighted:, die Cocoa Touch bei dieser Zustandsänderung aufruft.

- (void)setHighlighted:(BOOL)inHighlighted {
super.highlighted = inHighlighted;
if(inHighlighted) {
self.backgroundLayer.colors = self.highligthedColors;
}
else {
self.backgroundLayer.colors = self.normalColors;
}
}

Listing 5.38 Änderung des Farbverlaufs beim Drücken des Buttons


Galileo Computing - Zum Seitenanfang

5.3.4 Spieglein, Spieglein an der WandZur nächsten ÜberschriftZur vorigen Überschrift

Sie können auch auf den Layer-Inhalt zugreifen, beispielsweise um eine Spiegelung zu erzeugen. Die beiden Spiele verwenden einen View der Klasse NumberView, um ihre Spielstände anzuzeigen. In diesem View liegen jeweils drei Views der Klasse DigitView, die jeweils die einzelnen Ziffern darstellen. Der Numberview erzeugt auch eine gespiegelte, abgeschwächte Kopie der Ziffern, sodass der Eindruck einer glänzenden Oberfläche entsteht.

Abbildung

Abbildung 5.16 Beispiel für eine Spiegelung

Für einen Spiegelungseffekt müssen Sie eine vertikal gespiegelte und gestauchte Kopie des Originalbildes erstellen. Außerdem muss sich das gespiegelte Bild mit zunehmender Entfernung vom Originalbild abschwächen. Ein Beispiel für eine Spiegelung stellt Abbildung 5.16 dar, wo Sie diese drei Effekte – spiegelverkehrte Darstellung, Stauchung und Abschwächung – sehen können.

Tipp

Die Klasse NumberView spiegelt nach diesem Prinzip alle enthaltenen Views. Sie können die nachfolgend beschriebenen Methoden aus der Kategorie UIView(MirrorImage) auch in eigene View-Klassen integrieren, um Spiegelungen für beliebige Views zu erhalten.

Die erste und vielleicht auch schwierigste Aufgabe, um die Spiegelung zu erzeugen, ist die Bestimmung des Layerinhalts. Sie müssen dazu den Inhalt in ein Bild zeichnen. Die Klasse CALayer stellt für das Zeichnen der Layerhierarchie die Methode renderInContext: zur Verfügung. Die Erzeugung des Abbildes eines Views geschieht im Beispiel über die nützliche Methode mirroredImageWithScale: in der Kategorie UIView(MirrorImage):

- (UIImage *)mirroredImageWithScale:(CGFloat)inScale {
CALayer *theLayer = self.layer;
CALayer *thePresentationLayer =
[theLayer presentationLayer];
CGRect theFrame = self.frame;
CGSize theSize = theFrame.size;
CGContextRef theContext;
UIImage *theImage;

if(thePresentationLayer) {
theLayer = thePresentationLayer;
}
UIGraphicsBeginImageContext(theSize);
theContext = UIGraphicsGetCurrentContext();
CGContextScaleCTM(theContext, 1.0, -inScale);
CGContextTranslateCTM(theContext, 0.0, -theSize.height);
[theLayer setAllNeedsDisplay];
[theLayer renderInContext:theContext];
theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}

Listing 5.39 Erzeugung eines gespiegelten Abbildes eines Views

Das doppelte Layerchen

Core Animation verwendet für die Darstellung eines Layers zwei weitere Layer. Der Präsentationslayer enthält den aktuellen Zustand des Layers. In der Regel ist er einfach eine Kopie des Layers des Views. Während einer Animation unterscheiden sich aber die Werte der animierten Propertys des Präsentationslayers von dem Original, da der Präsentationslayer den aktuellen Animationszustand darstellt. Da die Spiegelung auch mit Animationen funktionieren soll, verwendet Listing 5.39 den Präsentationslayer des Layers, sofern er einen besitzt.

Die Erzeugung des Bildes in Listing 5.39 geschieht über einen Image-Context aus Core Graphics, der einen negativen, vertikalen Skalierungsfaktor erhält. Das negative Vorzeichen und der Wert 0,6 bewirken die Spiegelung und die Stauchung des Inhalts. Vor der Befüllung des Kontexts über den Aufruf der Methode renderInContext: müssen Sie die komplette Layerhierarchie für das Neuzeichnen markieren. Dazu senden Sie dem Layer und allen Sublayern die Nachricht setNeedsDisplay. Eine Ausnahme sind die Layer, die ihren Inhalt über die Property contents bereitstellen. Diese Aufrufe erfolgen über die rekursive Methode setAllNeedsDisplay der Kategorie CALayer(MirrorImage).

- (void)setAllNeedsDisplay {
if(self.contents == nil) {
[self setNeedsDisplay];
}
for(id theLayer in self.sublayers) {
[theLayer setAllNeedsDisplay];
}
}

Listing 5.40 Rekursives Markieren zum Neuzeichnen

Die Intensität der Farben des Spiegelbildes lässt mit zunehmender Entfernung vom Originalbild nach. Diesen Effekt können Sie in Core Graphics durch die Funktion CGContextClipToMask mit einem Verlauf als Maske erreichen. Die Maske für die Spiegelung ist ein Graustufenverlauf von 80 % bis 0 %. Der Kontext verwendet jeweils den Grauwert der Maske als Alphawert für den Pixel, sodass dunklere Grauwerte zu durchsichtigeren Pixeln führen.

- (void)drawMirrorWithScale:(CGFloat)inScale {
CGRect theFrame = self.frame;
CGSize theSize = theFrame.size;
CGPoint thePoint = CGPointMake(
CGRectGetMinX(theFrame), CGRectGetMaxY(theFrame));
CGFloat theHeight = theSize.height * inScale;
CGImageRef theGradient = [self createGradientImageWithSize:
CGSizeMake(1.0, theHeight) gray:0.8];
CGContextRef theContext = UIGraphicsGetCurrentContext();
UIImage *theImage = [self mirroredImageWithScale:inScale];
CGRect theRect;
theRect.origin = thePoint;
theRect.size = theSize;
CGContextSaveGState(theContext);
CGContextClipToMask(theContext, theRect, theGradient);
[theImage drawAtPoint:thePoint];
CGImageRelease(theGradient);
CGContextRestoreGState(theContext);
}

Listing 5.41 Zeichnen der Spiegelung mit einer Graustufenmaske

Die Methode drawMirrorWithScale: positioniert die Maske und das Spiegelbild an der linken unteren Ecke des Views. Dabei erzeugt die Methode createGradientImageWithSize:gray: einen Graustufenverlauf vom angegebenen Wert bis 0 %. Die Klasse NumberView ruft drawMirrorWithScale: über drawRect: auf (siehe Listing 5.42).

- (void)drawRect:(CGRect)inRect {
for(UIView *theView in self.subviews) {
[theView drawMirrorWithScale:SCALE];
}
}

Listing 5.42 Spiegelung der Subviews


Galileo Computing - Zum Seitenanfang

5.3.5 Der bewegte LayerZur nächsten ÜberschriftZur vorigen Überschrift

Sie können Layer auch mit Animationen versehen und sie so in Bewegung versetzen. Dadurch ergeben sich weitere Möglichkeiten für eine ansprechendere Oberflächengestaltung. Die Basisklasse für alle Animationen ist die Klasse CAAnimation. Die Layer verfügen über ein Animationsverzeichnis, und Sie können über die Methode addAnimation:forKey: dort Animationen einfügen. Durch das Einfügen animieren Sie den Layer, und Sie können eine Animation durch Entfernen aus diesem Verzeichnis auch wieder stoppen. Die bereits erwähnte Methode removeAllAnimations stoppt alle Animationen eines Layers auf einmal.

Die Property duration legt die Dauer der Animation fest. Für eine kontinuierliche Animation setzen Sie entweder die Property repeatCount oder repeatDuration auf einen Wert größer null. Während Sie über den ersten Wert die Anzahl der Wiederholungen vorgeben können, können Sie über den zweiten die Dauer der Animation festlegen. Wenn Sie die Property autoreverses auf YES setzen, ändert die Animation jeweils am Ende ihre Richtung.

Gibt es ein Leben nach der Animation?

Normalerweise entfernt der Layer eine abgelaufene Animation. Wenn Sie die Property removedOnCompletion des Animationsobjekts allerdings auf NO setzen, geschieht das nicht. Dadurch behält der Layer den Zustand bei, den er am Animationsende hatte. Andernfalls springt der Layer auf den Zustand, der den Werten seiner Propertys entspricht.

Dazu ein Beispiel: Ein Layer hat die Position (50, 50), und Sie starten eine Animation, die den Layer von Punkt (10, 10) zum Punkt (100, 10) verschiebt. Wenn die Animation endet und der Layer sie entfernt, springt der Layer an die Position (50, 50). Bleibt sie hingegen im Animationsverzeichnis des Layers, dann verharrt der Layer am Punkt (100, 10). Falls Sie aber später die Animation manuell entfernen, springt der Layer dann an den Punkt (50, 50).

Core Animation stellt Ihnen drei grundlegende Animationstypen zur Verfügung:

  • Property-Animationen
  • Transitionen
  • Animationsgruppen

Wir stellen Ihnen diese Typen im Folgenden genauer vor.

Property-Animationen

Dieser Animationstyp verändert den Wert einer Layer-Property während der Ausführung. Er basiert auf der Klasse CAPropertyAnimation, deren Objekten Sie den Keypath auf die zu animierende Property angeben müssen. Um diesen Animationstyp anzuwenden, verwenden Sie die Unterklassen CABasicAnimation und CAKeyframeAnimation. Alternativ kann die Animation aber auch den Schlüssel aus dem Animationsverzeichnis verwenden. Dadurch können Sie mit einem Animationsobjekt mehrere unterschiedliche Propertywerte animieren. Abhängig von der Property können dabei die Interpolationswerte Objekte der Klassen NSNumber (für Fließkommawerte) oder NSValue (für die Strukturen CGPoint, CGSize, CGRect und CATransform3D) sein.

Eine Animation der Klasse CABasicAnimation interpoliert zwischen zwei Propertywerten. Sie können dabei über die Propertys fromValue und toValue den Start- beziehungsweise den Endwert der Animation festlegen oder über die Property byValue den Abstand vom Start- oder Endwert angeben. Dabei sind unterschiedliche Kombinationen beim Setzen dieser Propertys möglich. Vier mögliche Kombinationen sind in Tabelle 5.5 dargestellt. Dabei bedeutet ein x in den drei linken Spalten, dass Sie die entsprechende Property im Animationsobjekt auf einen Wert ungleich von nil gesetzt haben.

Tabelle 5.5 Animationsbereich in Abhängigkeit von den gesetzten Propertys

fromValue byValue toValue Animation (von–nach)
x nil x fromValue toValue
x x nil fromValue fromValue + byValue
nil x x toValuebyValue toValue
x nil nil fromValue Aktueller
Propertywert

Das folgende Beispiel verschiebt einen Layer zwischen zwei Punkten. Als Propertynamen verwendet die Animation den Schlüssel, unter dem sie im Animationsverzeichnis des Layers liegt – also position.

CABasicAnimation *theAnimation = [CABasicAnimation animation];
theAnimation.fromValue =
[NSValue valueWithCGPoint:CGPointMake(10.0, 10.0)];
theAnimation.toValue =
[NSValue valueWithCGPoint:CGPointMake(100.0, 10.0)];
[theLayer addAnimation:theAnimation forKey:@"position"];

Listing 5.43 Verschieben eines Layers über eine Animation

Über die Klasse CAKeyframeAnimation können Sie Propertyanimationen mit komplexeren Verläufen erzeugen. Über die Property values übergeben Sie dabei ein Array mit den Werten für die Zwischenzustände der Animation. Falls Sie mit der Animation Werte vom Typ CGPoint animieren wollen, können Sie auch die Property path verwenden. Sie erwartet einen Core-Graphics-Pfad. Damit ist es beispielsweise einfach, einen Layer entlang einer Kreislinie zu bewegen:

CAKeyframeAnimation *theAnimation =
[CAKeyframeAnimation animation];
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathAddEllipseInRect(thePath, NULL,
CGRectMake(140.0, 150.0, 20.0, 20.0));
theAnimation.path = thePath;
theAnimation.repeatCount = 3;
theAnimation.autoreverses = YES;
theAnimation.duration = 0.5;
[theLayer addAnimation:theAnimation forKey:@"position"];
CGPathRelease(thePath);

Listing 5.44 Layer-Bewegung entlang eines Pfades

Sie finden dieses und noch andere Animationsbeispiele in der Klasse PieViewController im Projekt Pie auf der beiliegenden DVD.

Transitionen

Der zweite Animationstyp sind Transitionen, die Core Animation über die Klasse CATransition abbildet. Diese Klasse unterstützt insgesamt vier unterschiedliche Transitionstypen, die Tabelle 5.6 auflistet. Außer in der Fade-Animation können Sie eine Richtung in der Property subtype angeben. Diese drei Typen blenden den bestehenden View zusätzlich zur Bewegung noch aus.

Tabelle 5.6 Die Transitionstypen von Core Animation

Name Beschreibung
kCATransitionFade Blendet den bestehenden Layer aus und den neuen Layer ein.
kCATransitionMoveIn Schiebt den neuen Layer über den bestehenden.
kCATransitionPush Schiebt den neuen Layer herein und den bestehenden gleichzeitig hinaus.
kCATransitionReveal Schiebt den bestehenden Layer hinaus und gibt dadurch den neuen View frei.

Sie wenden eine Transition an, indem Sie sie in das Animationsverzeichnis desjenigen Layers einfügen, der die Transitionslayer enthält. Außerdem müssen Sie den bestehenden Layer unsichtbar machen, indem Sie ihn verstecken oder aus der Layer-Hierarchie entfernen. Analog müssen Sie den neuen Layer anzeigen oder in die Hierarchie einfügen. Listing 5.45 gibt ein einfaches Beispiel für diesen Animationstyp.

CATransition *theTransition = [CATransition animation];
theTransition.type = kCATransitionPush;
theTransition.subtype = kCATransitionFromTop;
[[theLayer.sublayers objectAtIndex:0] setHidden:YES];
[[theLayer.sublayers objectAtIndex:1] setHidden:NO];
[theLayer addAnimation: theTransition forKey:@"transition"];

Listing 5.45 Ausführen einer Transition

Animationsgruppen

Die Klasse CAAnimationGroup fasst mehrere Layeranimationen zu einer Gruppe zusammen, die Sie in einem Array an die Property animations übergeben. Die Gruppe gibt die maximale Dauer der Animationen vor und beendet die Ausführung längerer Animationen gegebenenfalls vorzeitig. Eine Animationsgruppe ist also die Queen unter den Animationen. Wenn sie aufhört zu essen, dann müssen auch alle anderen den Dessertlöffel weglegen. Hat also beispielsweise die Gruppe eine Dauer von einer Sekunde und enthält sie eine 4 Sekunden dauernde Animation, dann wird diese Animation nur zu einem Viertel ausgeführt. In Listing 5.46 führt diese Konfiguration beispielsweise dazu, dass die Animation des Eckradius nur von 0 bis 40 anstatt bis 160 läuft.

CABasicAnimation *theAnimation =
[CABasicAnimation animationWithKeyPath:@"cornerRadius"];
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theAnimation.toValue = [NSNumber numberWithFloat:160.0];
theAnimation.duration = 4.0;
theGroup.duration = 1.0;
theGroup.animations = [NSArray arrayWithObject:theAnimation];
theGroup.repeatCount = 3.0;
[theLayer addAnimation:theGroup forKey:@"group"];

Listing 5.46 Erzeugung einer Animationsgruppe


Galileo Computing - Zum Seitenanfang

5.3.6 Der View, der Layer, seine Animation und ihr LiebhaberZur nächsten ÜberschriftZur vorigen Überschrift

Mit einer Property-Animation können Sie aber nicht nur die Standardpropertys der Layer, sondern auch eigene Propertys animieren. Dazu sollten Sie diese Propertys analog zu der Property part in der Klasse PieLayer anlegen. Sie können also beispielsweise eine Animation der Klasse CABasicAnimation mit dem Schlüssel part in das Animationsverzeichnis eines Pie-Layers einfügen. Core Animation erzeugt dann während der Animation die entsprechenden Zwischenwerte für diese Property, sodass ein flüssiger Bewegungsablauf entsteht.

Bist Du flüssig?

Die Animationen in Core Animation sind zeit- und nicht framebasiert. Das heißt, dass die von Ihnen vorgegebene Zeit für die Animation wichtiger ist als die Anzahl der Einzelbilder (Frames). Core Animation berechnet, sofern das möglich ist, für die Animation so viele Einzelbilder, dass die Animation die vorgegebene Zeit nicht überschreitet und dabei trotzdem möglichst flüssig abläuft.

Dahinter steckt sicherlich jede Menge Hirnschmalz. Wenn Sie für Ihre Views und Layer Animationen brauchen, sollten Sie dafür Core Animation verwenden.

Mit den Methoden aus Abschnitt 5.2.2, »Animationen mit Blöcken«, ist es wesentlich einfacher, eine Animation zu erzeugen. Natürlich verwendet Cocoa Touch auch dafür Layeranimationen, die der Layer bei Änderungen der entsprechenden Property automatisch erzeugt. Dafür wäre es naheliegend, die Erzeugung der Animation in den Setter der Property des Views oder des Layers zu verschieben. Damit würden Sie aber die Animationserzeugung fest mit dem View oder dem Layer verdrahten.

Core Animation stellt stattdessen für die Animationserzeugung einen eleganteren Weg zur Verfügung. Ein Layer kann bei der Änderung einer Property oder der Veränderung der Layerhierarchie eine Aktion auslösen. Eine Aktion ist dabei ein Objekt, dessen Klasse das Protokoll CAAction implementiert. Die Propertyänderung besteht dabei aus drei Schritten. Zuerst versucht Core Animation über unterschiedliche Möglichkeiten eine Aktion zu erzeugen. Dann übernimmt der Layer den neuen Propertywert, und wenn die Erzeugung erfolgreich war, führt der Layer die Aktion aus (siehe Abbildung 5.17).

Abbildung

Abbildung 5.17 Animationserzeugung und -ausführung im Setter

Die Layer-Methode actionForKey: erzeugt die Aktionen des Layers. Wenn Sie die Standardaktionen eines Layers verändern oder neue Aktionen hinzufügen wollen, haben Sie mehrere Möglichkeiten:

  1. Sie können die Methode actionForLayer:forKey: im Delegate des Layers implementieren.
  2. Über die Property actions können Sie im Layer ein Verzeichnis für Aktionen setzen.
  3. Der Layer durchsucht sein Style-Verzeichnis rekursiv nach Aktionen.
  4. Sie können die Klassenmethode defaultActionForKey: implementieren.

Die Methode actionForKey: sucht in der angegebenen Reihenfolge nach den Aktionen. Wenn ein Suchweg dabei nil liefert, sucht der Layer weiter. Ein Aktionsobjekt oder der Rückgabewert [NSNull null] brechen die Suche sofort ab. Dabei bedeutet der Nullwert, dass der Layer keine Aktion zum angegebenen Schlüssel hat.

Das Protokoll CAAction besitzt nur eine Methode runActionForKey:object: arguments:, die der Layer aufruft, nachdem er den Propertywert oder die Layerhierarchie verändert hat. Dabei ist der Parameter object der Layer, der die Aktion ausgelöst hat. Der Parameter arguments ist in der Regel nil. Die Klasse CAAnimation implementiert das CAAction-Protokoll. Die Implementierung der Action-Methode fügt dabei das Animationsobjekt in das Animationsverzeichnis des Layers ein. Die genaue Implementierung lagert natürlich in einem geheimen Safe in Cupertino, aber sie könnte ungefähr so aussehen:

- (void)runActionForKey:(NSString *)inKey object:(id)inLayer
arguments:(NSDictionary *)inArguments {
[inLayer addAnimation:self forKey:inKey];
}

Listing 5.47 Action-Methode einer Animation

Wenn Sie also eigene Layerpropertys automatisch animieren möchten, brauchen Sie nur über einen der oben beschriebenen Suchwege ein Animationsobjekt zu erzeugen. Alternativ können Sie in Ihrer Layerklasse aber auch die Methode actionForKey: überschreiben.

- (id<CAAction>)actionForLayer:(CALayer *)inLayer
forKey:(NSString *)inKey {
if([@"part" isEqualToString:inKey]) {
CABasicAnimation *theAnimation =
[CABasicAnimation animationWithKeyPath:inKey];
theAnimation.fromValue = [inLayer valueForKey:@"part"];
return theAnimation;
}
else {
return [super actionForLayer:inLayer forKey:inKey];
}
}

Listing 5.48 Animationserzeugung für eine Layerproperty

Mit der Implementierung aus Listing 5.48 führt jede Änderung der Property part der Klasse PieView in einem Animationsblock zu einer animierten Veränderung der Grafik. Da der Layer die Aktion vor der Übernahme des Propertywertes anlegt, liefert der Aufruf von valueForKey: noch den alten Wert. Weil der Layer aber den Wert vor der Ausführung der Aktion übernimmt, reicht es nach Tabelle 5.5 aus, die Property fromValue zu setzen.

Das klingt ja schon mal ganz gut, hat aber noch einen kleinen Schönheitsfehler. Wenn Sie die Dauer des Animationsblocks verändern, ist das der Animation für die Property part völlig schnuppe. Leider hat Apple den Zugriff auf diesen und die anderen Animationsparameter sehr gut versteckt, sodass Sie diese Werte nicht einfach auslesen können.

Die Lösung dieses Problems ist aber einfach: Klauen wir gleich die ganze Animation. Die Methode erzeugt also das Animationsobjekt nicht selbst, sondern lässt es sich für eine Standardproperty erzeugen und passt diese an.

CABasicAnimation *theAnimation = 
(id)[super actionForKey:@"opacity"];
theAnimation.keyPath = inKey;
theAnimation.fromValue = self.part;
theAnimation.toValue = nil;
theAnimation.byValue = nil;

Listing 5.49 Erzeugung der Animation über eine Standardproperty

Listing 5.49 gibt den entsprechenden Codeschnipsel wieder, der die Animation über die Animation für die Property opacity erzeugt. Sie müssen in dieser Animation natürlich die Werte der Propertys keyPath und fromValue anpassen. Da Vorsicht bekanntlich die Mutter der Porzellankiste ist, sollten Sie die Propertywerte für toValue und byValue löschen. Sie können damit jetzt auch die Property part der Klasse PieView in einem Animationsblock setzen, um die Änderung zu animieren:

[UIView animateWithDuration:0.75 animations:^{
self.pieView.part = 0.6;
}];

Listing 5.50 Animation einer selbst definierten Property

Verwendung der Delegatemethode

Sie können dieses Vorgehen natürlich auch über die Delegatemethode actionForLayer:forKey: realisieren. Allerdings sollten Sie hier nicht die Delegatemethode der Superklasse, sondern die Methode actionForKey: des Layers aufrufen, um die Standardanimation zu erzeugen. Das hat zwei Gründe. Einerseits starten Sie hier eine neue Anfrage für eine andere Property, und dafür sollten Sie nicht die Delegatemethode, sondern die Methode des Layers verwenden. Für die Property opacity des Programmbeispiels soll der Layer ja alle Möglichkeiten der Animationserzeugung durchprobieren. Außerdem liefert Ihnen die Delegatemethode ein Objekt der Klasse NSNull, wenn Sie die Property nicht in einem Animationsblock verändern.

- (id<CAAction>)actionForLayer:(CALayer *)inLayer
forKey:(NSString *)inKey {
if([kPartKey isEqualToString:inKey]) {
CABasicAnimation *theAnimation =
(id)[inLayer actionForKey:@"opacity"];
theAnimation.keyPath = inKey;
theAnimation.fromValue =
[inLayer valueForKey:kPartKey]; theAnimation.toValue = nil;
theAnimation.byValue = nil;
return theAnimation;
}
else {
return [super actionForLayer:inLayer forKey:inKey];
}
}
Die Erzeugung der Aktion für die Standardpropertys erfolgt aber über den Superaufruf, da hier der Aufruf zu einer Endlosrekursion führen würde.


Galileo Computing - Zum Seitenanfang

5.3.7 Die 3. DimensionZur vorigen Überschrift

Im Gegensatz zu einem View befinden sich Layer in einem dreidimensionalen Raum. Über die Property zPosition legen Sie die Tiefenposition eines Layers fest, deren Standardwert null ist. Core Animation beschreibt also die Position eines Layers in einem dreidimensionalen Koordinatensystem, wie es Abbildung 5.18 darstellt.

Abbildung

Abbildung 5.18 Dreidimensionales Koordinatensystem der Layer

Sie können zwar die Layer darin räumlich transformieren (drehen, strecken oder verschieben). Aber die Layer selber bleiben natürlich flach. Beispielsweise verschwindet ein um 90° um die y-Achse gedrehter Layer. Die Transformation eines Layers beschreibt die C-Struktur CATransform3D, die eine 4×4-Matrix darstellt und auf die Sie über die Property transform zugreifen können.

Layer mit Tiefgang

Wenn Sie einen Layer drehen, sieht das aber nach wie vor flach aus. Eine Drehung um die x- oder y-Achse sieht eher wie eine Stauchung in y- beziehungsweise x-Richtung aus. Die Layer liegen zwar in einem dreidimensionalen Raum. Der hat aber noch keine Perspektive. Eine perspektivische Darstellung können Sie erreichen, wenn Sie einen kleinen Anteil der z-Position zu jeweils der x- und der y-Position hinzuaddieren. Das verkleinert weiter hinten liegende Layer und vergrößert weiter vorne liegende. Bei Layern mit Tiefe erzeugt das eine perspektivische Darstellung. Sie können bei einem Layer über die Property sublayerTransform eine Transformation für die Sublayer des Layers festlegen. Da Core Animation diese Transformation zusätzlich zu der Transformation des Sublayers anwendet, können Sie damit die Perspektivenberechnung durchführen.

CATransform3D theTransform = CATransform3DIdentity;
theTransform.m34 = 0.0005;
theParentLayer.sublayerTransform = theTransform;
Mit dieser Transformation stellt theParentLayer alle um die x- oder y-Achse gedrehten Sublayer perspektivisch dar.

Die 3D-Transformationen können Sie über Core-Animation-Funktionen erzeugen. Das geht ähnlich wie bei den 2D-Transformationen aus Core Graphics. Die Layer-Property transform lässt sich auch über Property-Animationen verändern. Dazu erzeugen Sie über den Convenience-Konstruktor valueWithCATransform3D: die gewünschten Werte.

CATransform3D theTransformation = CATransform3DMakeRotation(
M_PI / 3.0, 1.0, 1.0, 0.0);
CABasicAnimation *theAnimation = [CABasicAnimation animation];
theTransform = CATransform3DScale(theTransform, 0.5, 0.5, 0.5);
theAnimation.fromValue =
[NSValue valueWithCATransform3D:CATransform3DIdentity];
theAnimation.toValue =
[NSValue valueWithCATransform3D:theTransform];
[theLaver addAnimation:theAnimation forKey:@"transform"];

Listing 5.51 Dreidimensionale Layer-Animation

Die Anweisungen in Listing 5.51 erzeugen eine Animation mit einer 60°-Drehung ( / 3) und Stauchung auf die halbe Größe. Bei der Erzeugung einer Drehung im dreidimensionalen Raum müssen Sie die Rotationsachse beschreiben. Dies geschieht über drei Werte, die einen Punkt im Raum darstellen. Die Rotationsachse ist die (gedachte) Verbindungslinie des Nullpunkts mit diesem Punkt – das nennt man auch einen Vektor.

Drehungen über die Hauptachsen

Vorsicht, der Inhalt dieses Kastens kann Spuren von Mathematik enthalten. Das Lesen kann zu abstraktem Denken führen. Sie können Rotationen um einen beliebigen Vektor auch durch ein bis drei Rotationen an den Hauptachsen x, y und z beschreiben, indem Sie den Rotationsvektor auch durch Drehungen darstellen. Die Linie des Vektors (1, 1, 0) hat beispielsweise den Winkel 45° zur x-Achse, und somit können Sie diesen Vektor als 45°-Drehung um die z-Achse ausdrücken. Die Rotation aus Listing 5.51 können Sie also auch wie folgt beschreiben:

CATransform3D theTransformation = CATransform3DMakeRotation(
M_PI / 3.0, 1.0, 0.0, 0.0);
theTransform = CATransform3DRotate(theTransform,
M_PI / 4.0, 0.0, 0.0, 1.0);

In vielen Fällen reichen aber Rotationen, Skalierungen und Translationen an den drei Hauptachsen aus, die Sie über spezielle Animationspfade auch einfacher beschreiben können. Die Pfade haben einen ähnlichen Aufbau. Sie beginnen mit dem Wort transform, darauf folgen die Operation und der Name der Achse. Als Operationen stehen rotate, scale und translate zur Verfügung. Eine einfache Rotation können Sie beispielsweise so beschreiben:

CABasicAnimation *theAnimation = [CABasicAnimation animation];
theAnimation.fromValue = [NSNumber numberWithFloat:0.0];
theAnimation.toValue = [NSNumber numberWithFloat:M_PI / 2.0];
[theLayer addAnimation:theAnimation
forKey:@"transform.rotate.x"];

Listing 5.52 Dreidimensionale Animation über einen Animationspfad

Sie können den Namen der Achse auch weglassen, um die Werte für mehrere Achsen gleichzeitig zu setzen. Die Werte in den Property-Animationen müssen Sie dann als NSArray mit jeweils drei NSValue-Objekten übergeben:

CABasicAnimation *theAnimation = [CABasicAnimation animation];
theAnimation.fromValue = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.0], nil];
theAnimation.toValue = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:0.5], nil];
[theLayer addAnimation:theAnimation forKey:@"transform.scale"];

Listing 5.53 Animierte Skalierung entlang mehrerer Achsen



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