Die Apps, die Sie in den letzten beiden Kapiteln entwickelt haben, enthalten bereits viele Elemente, die Sie später wenn Sie ein erfahrener Programmierer geworden sind sehr oft wiederfinden werden. Sie haben gelernt, was MVC bedeutet und wie Sie Ihre Programme damit strukturieren können. Sie haben auch gelernt, wie Sie die existierenden Teile von Apples Entwicklungsumgebung einbinden und benutzen.
Es gibt aber Situationen, wo die grafischen Elemente, die Apple zur Verfügung stellt, alleine nicht ausreichen. Gerade für eine Spiele-App wie das Streichholzspiel aus dem vorhergehenden Kapitel wirkt eine reine Textanzeige wie viele Hölzer sind noch übrig? recht fade und langweilig. Hier sollte eigentlich das iPhone mehr bieten. Und genau das tut es auch. Daher lernen Sie in diesem Kapitel, wie Sie ein eigenes grafisches Element entwickeln: eine grafische Version des Streichholzhaufens!
iOS arbeitet grundsätzlich rein grafisch. Alles, was auf dem Bildschirm eines iPhones oder iPads angezeigt wird, ist ein grafisches Element. Selbst ein Label oder ein Textfeld zeigt Text als grafische Elemente an. Das erkennen Sie daran, dass Sie einerseits die Zeichensätze und -größen frei wählen können, andererseits aber auch die gleichen Koordinaten für Position und Größe angeben, die Sie auch andernorts für alle anderen grafischen Elemente verwenden.
Sie haben bereits in Kapitel 11 erfahren, wie Objekte die Eigenschaften und Methoden ihrer Basisklasse »erben« und wie Sie diese Fähigkeit geschickt nutzen, um sich Arbeit zu sparen. Wenn also unter iOS alle grafischen Elemente die gleichen Grundeigenschaften wie Position und Größe besitzen und alle grafischen Elemente Objekte sind, warum gibt es dafür dann keine allgemeine Basisklasse, die genau diese Grundeigenschaften besitzt und ansonsten nichts weiter tut?
Die Antwort ist ganz einfach: Eine solche Klasse gibt es durchaus! Sie nennt sich UIView
und ist die Vorlage für alle anderen grafischen Elemente, die auf dem iPhone-Bildschirm angezeigt werden können. UIView
ist verantwortlich sowohl für die Position auf dem iPhone-Bildschirm als auch für die Größe eines Elements. Ein UIView
kann ebenfalls schnell und einfach elegante Animationen erzeugen, die natürlich für alle anderen grafischen Elemente ebenfalls zur Verfügung stehen.
Das ganze Geheimnis eigener grafischer Elemente besteht nun darin, dass Sie eine neue Klasse anlegen, die UIView
als Basisklasse besitzt, und für diese Klasse dann eine eigene Darstellung implementieren. Die Benutzung eines eigenen grafischen Elements ist Ihnen bereits in Abschnitt 2.7 im Listing 2.3 begegnet. Hier möchte ich nun im Detail erläutern, was dort genau passiert ist.
Erinnern Sie sich zunächst einmal an Abbildung 12.5 in Abschnitt 12.1.3. Dort ging es um die Position und die Größe von grafischen Elementen auf dem iPhone-Bildschirm. Die Position ist der Abstand der linken oberen Kante eines Elements von der linken oberen Ecke des Bildschirms und die Größe wird in Breite und Höhe angegeben. Genau diese vier Zahlen fasst Swift bequem in einem sogenannten CGRect
zusammen. Ein CGRect
ist eine struct
, die von der Funktion CGRectMake
erzeugt wird. Dabei bekommt CGRectMake
die folgenden vier Parameter:
Diese vier Zahlen bestimmen ein Quadrat auf dem Bildschirm und dieses Quadrat entspricht genau der Fläche, die eine Unterklasse von UIView
auf dem Bildschirm einnimmt. Aber was bedeuten diese Zahlen? Sie beziehen sich auf die sogenannten Pixel. Dies ist eine Abkürzung für Picture Elements, was sich etwa mit Bildpunkten übersetzen lässt. Ein Bildpunkt ist dabei die kleinste Fläche, die Sie auf dem Bildschirm ansprechen können.
Bei einem modernen Retina-Display ist dies allerdings nicht mehr ganz richtig. Dort sind auch halbe Bildpunkte ansprechbar. So ist der Bildschirm eines iPhone 5 320 mal 568 Pixel groß. Damit belegt ein UIView
, das mit einem CGRect
der Form
let halbOben = CGRectMake(0, 0, 320, 284)
erzeugt wird, die gesamte obere Bildschirmhälfte eines iPhone 5. Und ein CGRect
der Form
let halbRechts = CGRectMake(160, 0, 160, 568)
belegt die gesamte rechte Bildschirmhälfte.
Wenn Sie wissen möchten, welche Position und Größe in einem CGRect
namens halbRechts
enthalten sind, so können Sie diese folgendermaßen abfragen:
halbRechts.origin.x
: Die x-Position, also der Abstand vom linken BildschirmrandhalbRechts.origin.y
: Die y-Position, also der Abstand vom oberen BildschirmrandhalbRechts.size.width
: Die BreitedasRechteck.size.height
: Die HöheWas machen Sie aber nun mit dem CGRect
? Glücklicherweise bietet die Klasse UIView
die Initialisierungsmethode mit Parameter frame
, mit der Sie ein UIView
erzeugen, das genau die Größe eines CGRect
einnimmt, also beispielsweise
// Die rechte Bildschirmhälfte auf einem iPhone 5s.
let halbRechts = CGRectMake(160, 0, 160, 568)
// Ein View, dass diese Fläche einnimmt.
let halbRechtsView = UIView(frame: halbRechts)
Nun ist UIView
die Basisklasse aller grafischen Elemente, die unter iOS angezeigt werden können. Das bedeutet, dass alle grafischen Elemente mit der oben gezeigten Methode angezeigt werden können und ihnen eine entsprechende Größe gegeben werden kann, also auch einem UILabel
.
Nun reicht das Erzeugen der Objekte alleine noch nicht aus, um sie auch anzuzeigen. Dazu müssen Sie ein erzeugtes Objekt auch noch zu einem bestehenden hinzufügen. Das heißt, es muss mindestens ein UIView
bereits angezeigt werden, damit Sie Ihr eigenes hinzufügen können. Dies hört sich schwieriger an, als es ist: Glücklicherweise bietet ein Bildschirm mit einem UIViewController
bereits das UIView
an, das dem Bildschirmhintergrund entspricht. In einer View-Controller-Klasse nennt sich dieses self.view
. Und die Methode, um ein neues zu einem existierenden View hinzuzufügen, nennt sich addSubview
. Das heißt, Sie können einfach das neu erzeugte View anzeigen, indem Sie in der Methode viewDidLoad
schreiben:
// Definiere ein Quadrat, das die rechte Bildschirmhälfte
// auf einem iPhone 5s ausfüllt.
let halbRechts = CGRectMake(160, 0, 160, 568)
// Definiere ein UIView mit diesem Quadrat.
let halbRechtsView = UIView(frame: halbRechts)
// Füge dieses UIView zum Bildschirm hinzu.
self.view.addSubview(halbRechtsView)
Damit Sie aber auch tatsächlich etwas sehen können, macht es Sinn, wenn Sie dem View eine eigene Farbe geben, zum Beispiel ein kräftiges Rot:
halbRechtsView.backgroundColor = UIColor.redColor()
Dabei ist backgroundColor
eine Eigenschaft, die die Hintergrundfarbe angibt. Da dies eine Eigenschaft von UIView
ist, können Sie diese Sie ahnen es schon bei allen grafischen Elementen setzen. Der Typ ist eine Klasse namens UIColor
und die Methode redColor()
erzeugt ein Objekt vom Typ UIColor
, das die Farbe Rot repräsentiert.
Erzeugen Sie in Xcode ein neues Projekt mit dem Namen »StreichholzAnzeiger« aus der Vorlage SINGLE VIEW APPLICATION und fügen Sie die obigen Zeilen Programmtext in die viewDidLoad
-Methode ein. Das Ergebnis wird dann ein Bildschirm sein, der in der linken Hälfte weiß und der rechten Hälfte rot ist.
Bei der Einrichtung von Bildschirmen habe ich Ihnen bisher immer eine Reihe von Ausrichtungsregeln genannt, mit denen Sie sichergestellt haben, dass die Anzeige auf verschiedenen Geräten mit verschiedenen Bildschirmgrößen und Orientierungen richtig funktioniert.
Das rote halbRechtsView
aus dem obigen Beispiel tut das nicht: Es funktioniert nur auf einem iPhone 5s und auch nur in der Portrait-Darstellung. Wenn Sie also wirklich eine App schreiben wollten, die auf verschiedenen Geräten und auch in der Landscape-Orientierung richtig arbeitet, so müssen Sie die Ausrichtungsregeln in Ihrem Programmtext berücksichtigen. Dies ist leider recht kompliziert und geht über den Rahmen dieses Buches hinaus.
Wenn Sie mehr darüber erfahren wollen, so empfehle ich Ihnen den »Auto Layout Guide: Understanding Auto Layout« in der Apple-Dokumentation. Die Klasse für Ausrichtungsregeln selbst lautet NSLayoutConstraint
.
Im Folgenden werde ich verschiedene Varianten vorstellen, eine grafische Streichholzanzeige ohne Ausrichtungsregeln mit festem Layout zu erzeugen. Für diesen Fall macht dieser Ansatz Sinn, denn für eine solche Anzeige wären Ausrichtungsregeln unnötig langsam und kompliziert. Die fertige Anzeige werden Sie dann in die »Streichholz«-App mit Ausrichtungsregeln einsetzen, wobei die Größe fest vorgegeben ist.
UIView
empfehle ich nur sehr bedingt, Ausrichtungsregeln zu verwenden. Sie sind sehr komplex und es ist zu leicht möglich, nur schwer zu entdeckende Fehler einzubauen. In diesem Fall sollten Sie die Positionen lieber selbst »von Hand« berechnen.Nun werden Sie zwei verschiedene Varianten von Streichhölzern bauen: Eine Variante durch einen Kombination von UIView
-Objekten und eine Variante durch echte grafische Linien und Anzeigen.
Mit Kombinationen von UIView
können Sie bereits grundsätzlich einen Streichholzhaufen programmieren: Sie basteln einfach eine Reihe von UIView
-Objekten, setzen die entsprechenden Farben und platzieren die Objekte so, dass sie aussehen wie Streichhölzer.
Abbildung 16.1 Ein einzelnes Streichholz, dargestellt durch die Klasse »StreichholzView«
Wie konstruieren Sie nun also das Streichholz aus den mehreren UIView
-Objekten? Die direkteste Möglichkeit besteht darin, zwei Objekte vom Typ UIView
zu erzeugen und deren Hintergrundfarben auf Rot (für den Streichholzkopf) und auf Gelb (für den Streichholzkörper) zu setzen. Diese Idee ist in Abbildung 16.1 gezeigt. Beachten Sie, dass Sie mit der Klasse StreichholzView
zwar einerseits eine eigene Klasse erzeugen, die eigene Funktionalität mitbringt, aber dennoch als Basisklasse UIView
besitzt. Andererseits benutzen Sie aber auch direkt zwei Objekte vom Typ UIView
, damit Sie Ihre eigene Funktionalität umsetzen können.
Dies passiert durchaus öfter, wenn Sie mit Objekten eigene Programme schreiben: Sie benutzen Objekte, wenn es nützlich und sinnvoll ist. Dabei können Sie durchaus die Basisklasse oder gar die Objekte selbst benutzen, mit denen Sie gerade arbeiten! Gerade bei UIView
kommt es häufig vor, dass Sie verschiedene Objekte, die alle UIView
als Basisklasse haben, ineinander verschachteln. So fügen Sie alle grafischen Elemente auf dem iPhone-Bildschirm ein, der immer eine Instanz von UIView
ist. Alle grafischen Elemente haben ihrerseits UIView
(in der Regel über mehrere weitere Vererbungen hinweg) als Basisklasse.
Wo und wie erzeugen Sie aber am besten diese zusätzlichen UIView
-Objekte? Genau dafür können Sie die Initialisierungsmethode init
mit dem Parameter frame
verwenden. Für diese Methode bietet sich ein bestimmtes Muster an, das von Apple vorgegeben ist: Sie kopieren eine Vorlage und fügen dann wieder Ihren eigenen Programmtext an der geeigneten Stelle ein.
Zu diesem Zweck fügen Sie eine neue Datei zum Projekt »StreichholzAnzeiger« hinzu und nennen sie StreichholzView.swift
. Dort schreiben Sie eine neue Klasse namens StreichholzView
mit Basisklasse UIView
. Das Ergebnis ist in Listing 16.1 abgedruckt. Diese Klasse erzeugt die Streichholz-Darstellung in zwei verschiedenen Situationen:
StreichholzView
-Objektes im Programmtext selbst mit dem Aufruf StreichholzView(frame:)
.
StreichholzView(coder:)
.
Beide init
-Methoden rufen eine Hilfsmethode setup()
auf, die die notwendigen Arbeiten übernimmt.
UIView
, beide init
-Methoden mit Parameter frame
und mit Parameter coder
zu implementieren. Damit kann Ihr eigenes View von anderen Programmierern ganz flexibel eingesetzt werden./// Darstellung eines einzelnen Streichholzes.
class StreichholzView: UIView {
/// Wird benutzt, um ein UIView im Programmtext zu erzeugen.
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
/// Wird benutzt, um ein UIView von einem Storyboard aus zu
/// erzeugen.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
/// Konstruiere alle Hilfsobjekte.
func setup() {
// Das Quadrat für den Streichholzkopf.
let kopfForm = CGRectMake(0, 0, 5, 10)
// Das Quadrat für den Streichholzkörper.
let koerperForm = CGRectMake(0, 0 + 10, 5, 45)
// Erzeuge ein UIView für den Kopf.
let kopf = UIView(frame: kopfForm)
// Erzeuge ein UIView für den Körper.
let koerper = UIView(frame: koerperForm)
// Mache den Kopf rot.
kopf.backgroundColor = UIColor.redColor()
// Mache den Körper gelb.
koerper.backgroundColor = UIColor.yellowColor()
// Füge Kopf und Körper zum aktuellen UIView hinzu.
self.addSubview(kopf)
self.addSubview(koerper)
}
}
Listing 16.1 Implementierung der Klasse »StreichholzView« zur Darstellung eines einzelnen Streichholzes
Eine Besonderheit (ich vermeide bewusst das Wort »Einschränkung«) gibt es allerdings noch:
Die grafische Darstellung in Abbildung 16.1 erlaubt nur eine feste Größe für ein Streichholz, nämlich 5 Pixel breit und 50 Pixel hoch. Grundsätzlich könnten Sie das Streichholz immer so skalieren, dass es das UIView
ausfüllt und entweder etwas größer oder etwas kleiner ist, je nachdem, welche Größe im Parameter frame
angegeben ist auch ohne Ausrichtungsregeln zu benutzen. Das sieht allerdings unter Umständen nicht gut aus zwei Klötzchen in Bildschirmgröße oder ein drei Millimeter großes Strichelchen wird niemand als Streichholz identifizieren können. Deswegen ist es an dieser Stelle sinnvoller, wenn Sie eine feste Größe vorschreiben, damit ein anderer Programmierer nicht versehentlich hässliche Streichhölzer erzeugt.
Das macht Apple genauso: Bestimmte Elemente wie beispielsweise ein Textfeld haben eine vorgegebene Höhe, die Sie nicht ohne Weiteres ändern können. Diese Größe sieht gut aus und funktioniert für die meisten Benutzer einwandfrei. Ändern dürfen Sie sie deswegen nur, wenn Sie eine komplett neue Textfeld-Klasse entwickeln (was wirklich eine Menge Arbeit ist).
Aus demselben Grund macht es an dieser Stelle Sinn, eine feste Größe vorzugeben und anderen Programmierern nicht zu erlauben, sie zu ändern! Das ist einer der Gründe, warum ich nicht empfehle, bei eigenen grafischen Anzeigen Ausrichtungsregeln zu benutzen.
import UIKit
/// Hauptbildschirm zum Testen der StreichholzAnzeige.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Definiere den Bereich, in dem das Streichholz angezeigt werden
// soll.
let streichholzBereich = CGRectMake(20, 20, 50, 100)
// Erzeuge ein StreichholzView.
let anzeige = StreichholzView(frame: streichholzBereich)
// Füge es zum Bildschirm hinzu.
self.view.addSubview(anzeige)
}
}
Listing 16.2 Implementierung der Klasse »ViewController« mit einem einzelnen Streichholz der Klasse »StreichholzView«
Um ein StreichholzView
mit einem einzelnen Streichholz einmal auszuprobieren, können Sie das grafische Element einfach direkt in der Methode viewDidLoad
der Klasse ViewController
einbauen und das Ergebnis begutachten, siehe Listing 16.2 . Starten Sie einmal die App und vergewissern Sie sich, dass Sie ein einzelnes kleines Streichholz in der linken oberen Ecke sehen!
Die gerade gezeigte Methode funktioniert ganz gut: Sie können damit beliebige Grafiken zusammensetzen und auch mehrere Streichhölzer darstellen. Sie hat allerdings den Nachteil, dass sie das »Legostein-Prinzip« benutzt: Wenn Sie mal Bilder haben, die nicht aus Rechtecken zusammengesetzt sind, geht das leider gar nicht. Eine Alternative haben Sie in Abschnitt 14.2.4 kennengelernt: Sie können Bilder zeichnen oder auch fotografieren und diese dann als »Image View« in Ihre App einfügen die entsprechende Klasse nennt sich UIImageView
. Damit lässt sich ein Bild von einem Streichholz anstelle der Klötzchen aus dem vorherigen Abschnitt verwenden.
In diesem Abschnitt möchte ich Ihnen eine weitere Alternative vorstellen, die ebenfalls die Einschränkung der Legoklötzchen aufhebt. Dabei benutzen Sie eine Methode namens drawRect
, die es erlaubt, beliebige Formen und Grafiken in Ihre eigene Klasse zu zeichnen, solange diese UIView
als Basisklasse besitzt.
Apple bietet zu diesem Zweck unter dem Namen Quartz 2D eine Reihe von sehr leistungsfähigen und flexiblen Grafikfunktionen an. Die meisten dieser Funktionen sind tatsächlich Funktionen und keine Methoden auf Objekten. Es gibt ein paar Objektaufrufe, aber für die meisten Aufgaben müssen Sie Funktionen verwenden. Eine vollständige Auflistung aller dieser Grafikfunktionen und ihrer vielfältigen Möglichkeiten würde den Rahmen dieses Buches bei Weitem sprengen, die vollständige ausführliche Anleitung finden Sie in der Apple-Dokumentation unter dem Namen »Quartz 2D Programming Guide«.
Die Grundfunktionen bestehen darin, beliebige Formen zu zeichnen und dabei die Strichstärken, Strichfarben und Füllfarben zu setzen. Weitergehende Funktionen (die ich im Folgenden allerdings nicht erläutern werde) erlauben es, beliebige Füllmuster (einschließlich Gradienten) zu wählen, Schatten hinzuzufügen und Grafiken zu strecken und zu drehen. Die letzte Funktionalität werde ich später allerdings für den Fall eines ganzen UIView
-Objekts für die Zwecke von Animationen beschreiben.
Die Grundlage der Grafikfunktionen ist der sogenannte Context, auf Deutsch könnte man ihn mit Prozesskontext übersetzen. Dieser Prozesskontext enthält die gerade gewählten Einstellungen für Strichstärke, Farben und Skalen. Außerdem weiß der Prozesskontext, in welchem View Sie gerade arbeiten. Wenn Sie eine neue Linie zeichnen, so werden diese Einstellungen benutzt, ohne dass Sie alle einzelnen Funktionen jedes Mal aufs Neue manuell setzen müssen. Umgekehrt können Sie mit einer einzelnen Änderung alle zukünftigen Operationen beeinflussen.
Der Prozesskontext ist vom Datentyp CGContext
und wird mit der Funktion UIGraphicsGetCurrentContext()
erzeugt. Wenn Sie diese Funktion innerhalb der Methode drawRect
mittels
let context = UIGraphicsGetCurrentContext()
aufrufen, so werden alle Funktionen, die sich auf die Variable context
berufen, innerhalb des zugehörigen UIView
ausgeführt. Für die Zwecke dieses Kapitels benötigen Sie die folgenden Funktionalitäten:
UIColor.yellowColor().set()
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 0.0, 1.0)
UIColor
.startX
und
startY
lauten, dann können Sie diese folgendermaßen als Startpunkt festlegen:
CGContextMoveToPoint(context, startX, startY)
weiterX
/weiterY
zu zeichnen, so verwenden Sie die folgende Funktion:
CGContextAddLineToPoint(context, weiterX, weiterY)
Eine solche Linie kann zu einem beliebigen anderen Punkt gehen. Dieser darf sogar außerhalb des Bildschirms liegen. Sie können diese Methode mehrfach hintereinander aufrufen, um längere Linien und damit komplexere Formen zu zeichnen.
CGContextMoveToPoint
und mehreren Aufrufen von CGContextAddLineToPoint
gezeichnet haben, so können Sie sie mit der Funktion CGContextDrawPath
füllen:
CGContextDrawPath(context, .FillStroke)
Dabei ist der erste Parameter wieder der bekannte Prozesskontext und der zweite, eine Aufzählung namens CGPathDrawingMode
, gibt an, dass die Fläche mit der Strichfarbe gefüllt werden soll. Es gibt hier noch eine Besonderheit:
Wenn die Fläche nicht geschlossen ist das heißt, der Startpunkt nicht gleich dem Endpunkt ist , dann wird noch eine weitere Begrenzungslinie automatisch eingefügt, die vom Endpunkt zurück zum Startpunkt läuft. Das zeige ich weiter unten am Beispiel.
CGRect
hineinpasst. Wenn das CGRect
den Namen kopfForm
besitzt, so können Sie die folgenden zwei Aufrufe benutzen:CGContextAddEllipseInRect(context, kopfForm)
CGContextDrawPath(context, .FillStroke)
Nun haben Sie die notwendigen Bausteine beisammen, um das Streichholz mit den Grafikfunktionen von Apple direkt zu zeichnen. Ein konkreter Vorschlag, wie das Streichholz aussehen könnte, ist in Abbildung 16.2 zu sehen. Zunächst wird der Körper des Streichholzes in gelber Farbe wie vorher als Rechteck gezeichnet. Dann kommt der Kopf in roter Farbe darauf, allerdings dieses Mal als Ellipse in einem Bereich, der etwas größer ist als vorher der Körper. Dadurch sieht das Streichholz besser aus.
Abbildung 16.2 Zeichnung eines einzelnes Streichholzes mit den Grafikfunktionen von Apple
import UIKit
/// Darstellung eines einzelnen Streichholzes.
class StreichholzViewAlt: UIView {
/// Wird benutzt, um ein UIView im Programmtext zu erzeugen.
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
/// Wird benutzt, um ein UIView von einem Storyboard aus zu
/// erzeugen.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
/// Konfiguriere dieses View.
func setup() {
// Setze den eigenen Hintergrund auf "durchsichtig"
// ("clearColor").
self.backgroundColor = UIColor.clearColor()
}
override func drawRect(rect: CGRect) {
// Speichere den aktuellen Prozesskontext in
// der Konstanten context.
let context = UIGraphicsGetCurrentContext()
// Zeichne den Streichholzkörper als Quadrat
// in gelber Farbe.
UIColor.yellowColor().set()
CGContextMoveToPoint(context, 5, 5)
CGContextAddLineToPoint(context, 10, 5)
CGContextAddLineToPoint(context, 10, 55)
CGContextAddLineToPoint(context, 5, 55)
// Fülle den Streichholzkörper mit der
// aktuellen Farbe (also Gelb).
CGContextDrawPath(context, .FillStroke)
// Zeichne den Streichholzkopf als Ellipse
// mit roter Farbe.
UIColor.redColor().set()
let kopfForm = CGRectMake(2, 0, 11, 20)
CGContextAddEllipseInRect(context, kopfForm)
// Fülle den Streichholzkopf mit der
// aktuellen Farbe (also Rot).
CGContextDrawPath(context, .FillStroke)
}
}
Listing 16.3 Implementierung der Klasse »StreichholzViewAlt« zur Darstellung eines einzelnen Streichholzes
Die konkrete Umsetzung ist in Listing 16.3 in der Klasse StreichholzViewAlt
zu sehen. In der setup
-Methode setze ich noch die Hintergrundfarbe des Views auf »durchsichtig« (die Farbe clearColor
), denn bei einem selbst gezeichneten View ist diese normalerweise Schwarz.
Zum Ausprobieren müssen Sie in diesem Fall nur in der Methode viewDidLoad
die Klasse StreichholzView
durch StreichholzViewAlt
ersetzen.
Die eigentliche Hauptarbeit passiert in der Methode drawRect
von StreichholzViewAlt
. Hier wird zunächst der passende Prozesskontext in der Konstanten context
gespeichert. Dann wird der Streichholzkörper in gelber Farbe als Rechteck gezeichnet. Beachten Sie, dass Sie hier nur die ersten drei Linien des Rechtecks selbst zeichnen müssen, die vierte Linie (vom Punkt (5, 55)
zum Startpunkt (5, 5)
) wird automatisch gezeichnet, sobald das Rechteckt mit der Funktion CGContextDrawPath
gefüllt wird.
Zuletzt wird der Streichholzkopf als Ellipse gezeichnet. Die Ellipse wird so gezeichnet, dass sie in ein Rechteck passt, das drei Pixel an jeder Seite breiter ist als der Streichholzkörper und fünf Pixel oberhalb des Körpers beginnt und 20 Pixel hoch ist vergleichen Sie das nochmals mit Abbildung 16.2. Anschließend wird die Ellipse in der Strichfarbe (in diesem Fall ist es die rote Farbe) gefüllt. Und fertig ist das gesamte Streichholz!
Nun wollen Sie ja eigentlich nicht nur einzelne Streichhölzer malen, sondern in Wahrheit den ganzen Streichholzhaufen grafisch darstellen. Das ist jetzt kein Problem mehr! Wo Sie jetzt schon ein einzelnes Streichholz zeichnen können, ist es bis zum Haufen auch nicht mehr weit.
Um dieses Ziel zu erreichen, erzeugen Sie eine weitere Klasse namens HaufenView
mit Basisklasse UIView
. Die Aufgabe des HaufenView
besteht darin, die gewünschte Anzahl von StreichholzView
-Objekten zu erzeugen und an der richtigen Position darzustellen. Der Bequemlichkeit halber soll HaufenView
ähnliche Methoden wie das Datenmodell besitzen:
setzeHoelzer
Stellt eine bestimmte Zahl Hölzer auf einmal dar. Diese Methode soll benutzt werden, um die anfängliche Zahl anzuzeigen.entferneHoelzer
Entfernt eine bestimmte Zahl Hölzer. Diese Methode soll im Spielverlauf benutzt werden, um Hölzer zu entfernen.Die letzere Methode scheint nicht unbedingt nötig zu sein, denn im Gegensatz zum Datenmodell ist es nicht die Aufgabe der Präsentation, sich damit zu beschäftigen, wie viele Hölzer entfernt werden dürfen. Sie hat allerdings einen bestimmten Sinn, wie Sie im nächsten Abschnitt über Animationen sehen werden.
Um die einzelnen Hölzer darzustellen, benutzen Sie wieder die Methode addSubview
der Basisklasse UIView
von HaufenView
. Sie können umgekehrt auch die Sammlung aller Objekte, die mit addSubview
hinzugefügt wurden, bekommen, indem Sie die Eigenschaft subviews
eines jeden UIView
-Objekts abfragen. Der Rückgabewert ist ein Array
, also liefert beispielsweise
let hoelzerViews = self.subviews
innerhalb einer Methode der Klasse HaufenView
alle StreichholzView
-Objekte, die es vorher mit addSubview
hinzugefügt hat.
Um ein einzelnes StreichholzView
anschließend wieder zu entfernen, benutzen Sie die Methode removeFromSuperview
des StreichholzView
-Objekts. Dies ist eine wichtige Besonderheit von UIView
-Objekten: Während Sie die addSubview
-Methode von HaufenView
benutzen, um neue Views hinzuzufügen, müssen Sie eine Methode nämlich removeFromSuperview
von StreichholzView
benutzen, um es wieder zu entfernen. Sie können ein View nicht direkt aus einem anderen View entfernen, zu dem Sie es hinzugefügt haben! Stattdessen müssen Sie das hinzugefügte View bitten, sich selbst wieder zu entfernen!
Eine letzte Frage müssen Sie noch beantworten, bevor Sie die Klasse HaufenView
implementieren: Wie sollen mehrere Streichhölzer am Bildschirm dargestellt werden? Sie sollen minimal kein Holz und maximal 24 Hölzer gleichzeitig darstellen können. Die minimale Größe eines Streichholzes der Klasse WSStreichholzView
ist 20 Pixel breit und 55 Pixel hoch, wobei Sie sinnvollerweise etwas Platz in alle Richtungen übrig behalten sollten. Deswegen ist es besser, wenn Sie eine Breite von 30 Pixeln einplanen und eine Höhe von 80 Pixeln. Wenn Sie noch jeweils zehn Pixel an den Bildschirmrändern übrig lassen, so verbleibt eine Breite von 300 Pixeln, auf der Sie Hölzer platzieren können damit passt ein HaufenView
eigentlich immer auf den Bildschirm auch des kleinsten iPhones. Dies entspricht bei 30 Pixeln pro Holz insgesamt zehn Hölzern nebeneinander. In der Höhe brauchen Sie dann drei Zeilen, um insgesamt zwei volle Reihen (mit jeweils zehn Hölzern) und eine halbvolle Reihe (mit vier Hölzern) darstellen zu können. Bei einer Höhe von 80 Pixeln pro Streichholz sind das insgesamt 240 Pixel Höhe.
Erzeugen Sie nun eine neue Datei namens HaufenView.swift
und schreiben Sie dort die Implementierung aus Listing 16.4 hinein. Die Methode setzeHoelzer
funktioniert folgendermaßen:
StreichholzView
werden entfernt. Diese sind alle Subviews des HaufenView
, weswegen sie mit der Methode subviews
als Array
zurückgeliefert werden. Dann wird auf jedes einzelne die Methode removeFromSuperview
angewendet. Beachten Sie, dass die Schleife nicht durchlaufen wird, wenn subviews
ein leeres Array zurückliefert.
Für die Methode entferneHoelzer
können Sie sich die Arbeit besonders einfach machen: Sie bekommen nämlich wieder über die Eigenschaft subviews
alle vorhandenen Hölzer als Array
. In Abschnitt 10.1.1 haben Sie gesehen, wie Sie die Methode last
last
eines Array
benutzen, um das jeweils letzte Objekt zu bekommen. Dieses können Sie direkt entfernen. Wenn Sie diese Methode nun einfach anzahl
-mal hintereinander aufrufen, wird die gewünschte Anzahl Hölzer automatisch entfernt.
import UIKit
/// Anzeige einer Sammlung von Streichhölzern.
class HaufenView: UIView {
/// Wird benutzt, um ein UIView im Programmtext zu erzeugen.
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
/// Wird benutzt, um ein UIView von einem Storyboard aus zu
/// erzeugen.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
/// Konfiguriere dieses View.
func setup() {
// Setze den eigenen Hintergrund auf
// "durchsichtig" ("clearColor").
self.backgroundColor = UIColor.clearColor()
}
/// Setze eine feste Anzahl von Hölzern.
func setzeHoelzer(anzahl: Int) {
// Entferne alle alten Hölzer.
let alteHoelzer = self.subviews
for holz in alteHoelzer {
holz.removeFromSuperview()
}
// Bestimme die Zahl der notwendigen Zeilen.
let zeilen = anzahl / 10
// Bestimme die Zahl der Hölzer in der letzten Zeile.
let anzahlLetzteZeile = anzahl -- (zeilen * 10)
// Zeichne alle vollen Zeilen.
for var zeile=0; zeile<zeilen; zeile+=1 {
for var spalte=0; spalte<10; spalte+=1 {
// Bestimmte die Position eines Streichholzes
// aus Zeile und Spalte.
let position = CGRectMake(CGFloat(10+spalte*30),
CGFloat(0+zeile*80),
30, 80)
// Erzeuge ein neues StreichholzView an der
// gewünschten Position.
let streichholz = StreichholzView(frame: position)
// Füge es hinzu.
self.addSubview(streichholz)
}
}
// Zeichne die letzte Zeile.
for var spalte=0; spalte<anzahlLetzteZeile; spalte+=1 {
// Bestimme die Position eines Streichholzes der
// letzten Zeile.
let position = CGRectMake(CGFloat(10+spalte*30),
CGFloat(0+zeilen*80),
30, 80)
// Erzeuge ein neues WSStreichholzView an der
// gewünschten Position.
let streichholz = StreichholzView(frame: position)
// Füge es hinzu.
self.addSubview(streichholz)
}
}
/// Entferne eine bestimmte Zahl von Hölzern.
func entferneHoelzer(anzahl: Int) {
// Entferne eine bestimmte Zahl von Hölzern.
for var i=0; i<anzahl; i+=1 {
// Entferne das letzte Holz (wenn es existiert).
self.subviews.last?.removeFromSuperview()
}
}
}
Listing 16.4 Implementierung der Klasse HaufenView
zur Darstellung aller Streichhölzer
Sie können Ihren neuen HaufenView
direkt im vorhandenen Projekt »StreichholzView« ausprobieren, indem Sie die viewDidLoad
-Methode der Klasse ViewController
wie in Listing 16.5 gezeigt modifizieren.
override func viewDidLoad() {
super.viewDidLoad()
// Bestimme Position und Größe des Haufens.
let haufenPosition = CGRectMake(10, 10, 300, 240)
// Erzeuge das WSHaufenView--Objekt.
let haufen = HaufenView(frame: haufenPosition)
// Füge es zum Bildschirm hinzu.
self.view.addSubview(haufen)
// Setze die Zahl der Streichhölzer auf 24.
haufen.setzeHoelzer(24)
}
Listing 16.5 Einbinden der neuen Klasse »HaufenView« zur Darstellung aller Streichhölzer
Starten Sie die App und vergewissern Sie sich, dass sie richtig funktioniert, wenn Sie eine unterschiedliche Zahl von Hölzern zwischen 0 und 24 angeben. Genau genommen funktioniert sie sogar für bis zu 30 Hölzer, obwohl diese Funktionalität gar nicht benötigt wird.
Sie haben jetzt schon eine funktionierende Darstellung eines Streichholzhaufens und können diese Darstellung im eigentlichen Streichholzspiel verwenden. Ich zeige Ihnen aber jetzt noch etwas ganz Besonderes: nämlich die Möglichkeit, verschwindende Streichhölzer grafisch zu animieren! Und das Beste dabei: Sie müssen nur ganz wenig eigenen Programmtext dafür schreiben, da die Klasse UIView
Ihnen bereits einen Großteil der Arbeit abnimmt!
Zunächst einmal möchte ich einige neue Eigenschaften aller UIView
-Objekte vorstellen und bei dieser Gelegenheit auch diejenigen wiederholen, die Sie bereits kennen. Eine neue Eigenschaft ist die Eigenschaft alpha
. Dies ist eine Fließkommazahl zwischen 0 und 1, die die Transparenz, also die Durchsichtigkeit, angibt. Dabei bedeutet 0, dass das Objekt vollständig durchsichtig ist, und 1, dass es vollständig opak, also nicht durchsichtig ist. Die Farbe clearColor
hat beispielsweise einen alpha
-Wert von 0 und ist daher vollständig transparent.
Die Eigenschaft alpha
ist übrigens die gleiche Zahl, die Sie bereits beim letzten Parameter der Funktion CGContextSetRGBStrokeColor
kennengelernt haben.
Schließlich gibt es die Eigenschaft transform
, die es erlaubt, das UIView
zu drehen und zu strecken. Dies wird durch einen Datentyp namens CGAffineTransform
ausgedrückt. Um diese Drehungen und Streckungen vollständig zu verstehen, ist allerdings eine Menge Mathematik erforderlich. Zum Glück hat Apple Hilfsfunktionen geschaffen, die Ihre Arbeit erheblich erleichtern und Ihnen ein paar Monate Mathematikstudium ersparen. Die zwei wichtigsten Funktionen sind die folgenden:
CGAffineTransformMakeRotation(alpha)
Diese Funktion bekommt einen Winkel als Parameter und liefert eine Drehung gegen den Uhrzeigersinn. Der Winkel 0 entspricht keiner Drehung und positive Werte drehen das UIView
gegen den Uhrzeigersinn. Eine halbe Drehung ist durch die Konstante π gegeben. Dieser Zahlenwert ist in der KonstantenM_PI
definiertundbeträgt3,14159265358979323846264338327950288,falls Sie mal damit angeben möchten.CGAffineTransformMakeScale(sx, sy)
Diese Funktion skaliert ein UIView
sowohl in x- als auch in y-Richtung. Der erste Parameter ist die Skalierung in x-, der zweite die in y-Richtung. Sind beide Werte gleich 1, so macht die Skalierung gar nichts.Tabelle 16.1 fasst nochmals die wichtigsten Eigenschaften, die Sie an einem UIView
einstellen können, zusammen.
Eigenschaft | Datentyp | Bedeutung |
frame | CGRect | Bildschirmposition und -breite |
backgroundColor | UIColor | Hintergrundfarbe |
alpha | CGFloat | Durchsichtigkeit (von 0 bis 1) |
transform | CGAffineTransform | Drehung und Streckung |
Tabelle 16.1 Einige Eigenschaften eines »UIView«-Objekts, die Sie verändern können
Warum habe ich diese Eigenschaften aufgelistet? Der Grund ist, dass das UIView
alle diese Eigenschaften grafisch während einer Animation verändern kann! Sie können beispielsweise ein Streichholz »umwerfen« und gleichzeitig ausblenden. Oder Sie können es ganz klein werden lassen, sodass es schließlich ganz verschwindet!
Die Methode, mit der Sie diese ganze »Magie« bewirken können, nennt sich animateWithDuration
und ist eine Klassenmethode, siehe auch den fortgeschrittenen Abschnitt 11.4.4. Diese Methode hat als ersten Parameter die Zeitdauer der Animation in Sekunden. Von dieser Methode gibt es verschiedene Varianten mit unterschiedlicher Anzahl von Parametern. Im Folgenden bespreche ich die Form
UIView.animateWithDuration(3.0, // Dauer in Sekunden.
animations: { () in
// Resultat der Animation.
}, completion: { (Abgebrochen: Bool) in
// Abschluss der Animation.
})
Der zweite Parameter mit Namen animations
bekommt einen Block, in dem die Resultate der Animation beschrieben werden. Also alle Eigenschaften von allen Views auf dem Bildschirm, die nach dem Ende der Animation gesetzt werden sollen. Dadurch können Sie mit wenigen Zeilen Programmtext sehr komplizierte Abläufe und Animationen erreichen! Wollen Sie beispielsweise die Hintergrundfarbe von Rot auf Schwarz ändern, so setzen Sie innerhalb des Blocks
self.backgroundColor = UIColor.blackColor()
und die Klasse UIView
macht den Rest die ganzen Umrechnungen, Zwischenfarbtöne, Verlaufskurven und so weiter. Glauben Sie mir, wenn Sie das alles per Hand selbst erledigen müssten, würde es Ihnen bestimmt keinen Spaß machen!
Der dritte Parameter mit Namen completion
ist ein Block mit einem Parameter, der angibt, ob die Animation komplett durchgelaufen ist oder abgebrochen wurde. Sie können diesen Parameter ignorieren, wenn Sie diese Information nicht brauchen.
Beachten Sie, dass Sie sich nicht selbst darum kümmern müssen, wann und wie die Blöcke aufgerufen werden, sondern Sie müssen diese lediglich angeben und UIView
kümmert sich um den Rest! Diese Art von Blöcken, die als eigener Datentyp übergeben werden, ist näher im fortgeschrittenen Abschnitt 10.6.1 beschrieben.
/// Entferne eine bestimmte Zahl von Hölzern.
func entferneHoelzer(anzahl: Int) {
// Array mit allen StreichholzView--Instanzen.
let alteHoelzer = self.subviews
// Bestimme die Zahl der zu entfernenden Hölzer.
// Sie darf höchstens so groß sein, wie Hölzer noch da sind.
let entferneZahl: Int
if anzahl > self.sichtbareHoelzer {
entferneZahl = self.sichtbareHoelzer
} else {
entferneZahl = anzahl
}
// Schleife über die Anzahl der zu entfernenden Hölzer.
for var i=1; i<=entferneZahl; i+=1 {
// Index des letzten Holzes, das entfernt werden soll.
let letztes = self.sichtbareHoelzer -- i
// Die konkrete Instanz, die entfernt werden soll.
let altesHolz = alteHoelzer[letztes]
// Löse die Animation aus.
UIView.animateWithDuration(1.0,
animations: { () in
// Setze die Transparenz am Ende auf
// 0, also vollständig durchsichtig.
altesHolz.alpha = 0.0
}, completion: { (_ : Bool) in
// Am Ende entferne das Holz vom
// Bildschirm.
altesHolz.removeFromSuperview()
})
}
// Reduziere die Anzahl der sichtbaren Hölzer.
self.sichtbareHoelzer = self.sichtbareHoelzer -- anzahl
}
Listing 16.6 Alternative Implementierung der Methode »entferneHoelzer« der Klasse »HaufenView«, die eine kurze Animation benutzt
Nun können Sie die Animation umsetzen. Zunächst lassen Sie die gewünschte Zahl von Hölzern einfach »verschwinden«, indem Sie diese durchsichig darstellen. Dafür gibt es die Eigenschaft alpha
, die vor Beginn der Animation auf den Wert 1 eingestellt ist. Innerhalb des ersten Blocks setzen Sie den Wert auf 0 und iOS kümmert sich für Sie um den Rest.
Es gibt aber noch eine Schwierigkeit, um die Sie sich kümmern müssen: Wenn Sie die Animationsmethode aufrufen, so geben Sie die Animationsdauer in Sekunden an. Die Methode ist allerdings sofort beendet, das heißt, Ihr Programm kann in aller Ruhe weiterlaufen, während iOS ohne Ihre Hilfe die Animation durchführt. Dies ist einerseits sehr gut für Sie Sie haben weniger Arbeit. Andererseits können Sie sich nicht mehr darauf verlassen, dass Sie mit dem alten Aufruf
self.subviews().lastObject()
aus Listing 16.4 in einer Schleife auch wirklich das letzte Streichholz erwischen. Hier müssen Sie leider immer davon ausgehen, dass die Animation noch nicht fertig ist und die ganzen StreichholzView
-Objekte in Wahrheit immer noch im Array self.subviews()
enthalten sind.
Es kann sogar noch schlimmer kommen: Wenn Sie die Methode entferneHoelzer
gleich zweimal hintereinander aufrufen, so ist vielleicht die alte Animation noch nicht fertig und auch die »alten« Streichhölzer des letzten Aufrufs sind noch gar nicht verschwunden!
Deswegen brauchen Sie eine zusätzliche Variable, die Ihnen genau sagt, wie viele Hölzer denn gerade noch übrig sind. Dann können Sie immer diese Zahl benutzen, um festzustellen, an welcher Stelle denn das nächste Holz entfernt werden soll. Zu diesem Zweck fügen Sie eine zusätzliche Eigenschaft
/// Anzahl der gerade angezeigten Hölzer.
var sichtbareHoelzer: Int = 0
zur Klasse HaufenView
hinzu. Am Ende der Methode setzeHoelzer
auf anzahl
:
// Aktuell sichtbare Zahl von Hölzern.
self.sichtbareHoelzer = anzahl
Dann können Sie die Methode entferneHoelzer
in der Implementierung neu schreiben, sodass sie nun Animationen benutzt. Dies ist in Listing 16.6 gezeigt.
Fügen Sie einmal eine Zeile in viewDidLoad
in der Implementierung der Klasse ViewController
ein, die die Animation benutzt:
// Setze eine Anfangszahl von 24 Hölzern.
haufen.setzeHoelzer(24)
// Entferne 5 davon mit einer Animation.
haufen.entferneHoelzer(5)
und vergewissern Sie sich, dass die Animation korrekt funktioniert.
Eine weitere, etwas anspruchsvollere Animation erhalten Sie, indem Sie die Hölzer nicht nur einfach verschwinden, sondern sogar umfallen lassen. Dafür können Sie eine Drehung verwenden, indem Sie die Eigenschaft transform
geeignet setzen. Probieren Sie es einfach mal aus, indem Sie eine Drehung um einen Viertelkreis wie folgt definieren:
let drehung = CGAffineTransformMakeRotation(CGFloat(M_PI/2))
Da eine Drehung um die Konstante M_PI
einer halben Drehung entspricht, erzeugt die Funktion CGAffineTransformMakeRotation
mit dem Parameter M_PI/2
genau eine Vierteldrehung. Setzen Sie nun innerhalb des Animationsblocks die transform
-Eigenschaft auf diesen Wert:
// Drehung zur "umgefallenen" Position.
let drehung = CGAffineTransformMakeRotation(CGFloat(M_PI/2))
// Löse die Animation aus.
UIView.animateWithDuration(1.0,
animations: { () in
// Setze die Transparenz am Ende auf
// 0, also vollständig durchsichtig.
altesHolz.alpha = 0.0
// Drehe das Holz, sodass es am Ende
// der Animation auf der Seite liegt.
altesHolz.transform = drehung
}, completion: { (_ : Bool) in
// Am Ende entferne das Holz vom
// Bildschirm.
altesHolz.removeFromSuperview()
})
und überzeugen Sie sich, dass die Streichhölzer nun alle sichtbar »umfallen«, während sie gleichzeitig verschwinden!
Auf diesem Wege können Sie sehr aufwendige Animationen erzeugen und kombinieren. Es ist sogar möglich, Animationen zu unterschiedlichen Zeiten zu starten und zu beenden, beispielsweise könnten Sie die Streichhölzer schneller umfallen lassen, als sie verschwinden.
Die Klasse HaufenView
und die dazugehörige Hilfsklasse StreichholzView
(oder alternativ auch StreichholzViewAlt
) können Sie nun in die eigentliche »Streichholz«-App aus Kapitel 15 einbauen. Zunächst erzeugen Sie die zwei Hilfsklassen HaufenView
und StreichholzView
innerhalb des Projekts und kopieren dann die Inhalte der Dateien mit Copy & Paste aus dem Testprojekt »StreichholzView«. Jetzt können Sie das eigentliche neue View in die App einbauen.
Eine Hürde müssen Sie aber noch nehmen: Der grafische Editor von Xcode kennt zwar verschiedene grafische Elemente wie Slider und Labels, aber er kennt leider nicht Ihr HaufenView
. Sie könnten es natürlich im Programmtext jederzeit selbst erzeugen, aber Sie hatten ja bereits den ganzen Rest der grafischen Oberfläche in Xcode erzeugt. Da wäre es schade, wenn Sie die grafische Oberfläche nun selbst erzeugen müssten! (Und Sie müssten auch die Ausrichtungsregeln in Ihrem Programmtext erzeugen. Also lieber nicht so!)
Abbildung 16.3 Löschen der Ausrichtungsregel »Top Space to: Zug Anzeige« des ersten Buttons
Abbildung 16.4 Ausrichtungsregel von fester Größe eines »UIView«-Objekts in Xcode
Deswegen bauen Sie das View in Ihre App ein, ohne auf den Komfort des grafischen Editors verzichten zu müssen. Zunächst empfehle ich Ihnen, die drei Buttons »Nimm 1«, »Nimm 2«, und »Nimm 3« nach unten zu ziehen und im fünften Reiter jedes einzelnen Buttons die Ausrichtungsregel TOP SPACE TO: ZUG ANZEIGE zu löschen, siehe Abbildung 16.3.
Dann fügen Sie zunächst ein UIView
mithilfe von Xcode in die App ein. Dieses generelle Objekt finden Sie in der Liste als VIEW, es ist sehr weit unten (das vorletzte Objekt in Xcode 7.1). Platzieren Sie es unterhalb des »Zuganzeige«-Labels und setzen Sie die Ausrichtungsregeln:
UIView
) auf 30 Pixel setzt.
Dann ändern Sie im dritten Reiter des neuen UIView
in der obersten Gruppe CUSTOM CLASS die CLASS auf »HaufenView«, Abbildung 16.5. Dadurch haben Sie jetzt eine Klasse vom Typ HaufenView
in der richtigen Größe eingefügt.
Abbildung 16.5 Ändern der Klasse des »UIView« auf »HaufenView«
Nun können Sie dieses HaufenView
auf dem bekannten Weg mit einer Eigenschaft in ViewController
verknüpfen. Beachten Sie, dass die Eigenschaft dabei automatisch die korrekte Klasse HaufenView
bekommt. Nennen Sie die Eigenschaft haufenAnzeige
:
/// Grafische Darstellung des Spielhaufens.
@IBOutlet weak var haufenAnzeige: HaufenView!
Nun fügen Sie an allen Stellen, an denen im Moment die Streichholzanzahl ins Label streichHolzAnzeige
geschrieben wird, die relevanten Methodenaufrufe für die haufenAnzeige
ein.
Dies ist im Einzelnen:
neuesSpiel
fügen Sie am Ende ein:
// Anpassen der grafischen Streichholzanzeige.
self.haufenAnzeige.setzeHoelzer(self.spielHaufen.hoelzer)
spielerZug
fügen Sie am Anfang die Zeile ein:
self.haufenAnzeige.entferneHoelzer(zahl)
spielerZug
fügen Sie in der Zeile unterhalb von
let computerZahl = self.computerStrategie.macheZug()
self.haufenAnzeige.entferneHoelzer(computerZahl)
ein. Dadurch entfernt auch der Computer bei seinem Zug die korrekte Anzahl von Streichhölzern.
Starten Sie nun die App neu und vergewissern Sie sich, dass die Streichhölzer korrekt grafisch angezeigt werden und mit einer kleinen Animation verschwinden, sobald Sie oder der Computer einen Zug machen. Vergewissern Sie sich ebenfalls, dass das Spiel noch genauso richtig funktioniert wie vorher!
Abbildung 16.6 zeigt ein paar Beispiele des Verlaufs des Streichholzspiels. Ich wünsche Ihnen viel Spaß dabei!
Abbildung 16.6 Ein paar Beispiele aus dem Streichholzspiel
entferneHoelzer
in Listing 16.6 so, dass die Animation für das Verschwinden halb so schnell passiert wie die Animation für das Umfallen.
entferneHoelzer
in Listing 16.6 so, dass das Verschwinden erst dann gestartet wird, nachdem die Hölzer umgefallen sind.Hinweis: Sie können Aufrufe in Blöcken ineinanderschachteln!
entferneHoelzer
in Listing 16.6 so, dass die Animationen unterschiedlich lange dauern: Und zwar soll eine Animation zwischen 0,5 und 1,5 Sekunden dauern und die Dauer soll durch eine Zufallszahl erzeugt werden.