Sergiy Krutykov

iPhone bietet eine gewisse Auswahl an Steuerelementen an, die Entwickler in ihren Programmen benutzen können. Jedoch reicht diese Auswahl für eine gemäße Gestaltung der Applikation häufig nicht aus. Bei manchen Applikationen, wie zum Beispiel bei Spielen, die in erster Linie originelles Aussehen aufweisen sollen, sind solche Standard-GUI-Elemente fast schon tabu, so dass man sowieso gezwungen ist, eigene Elemente zu implementieren. Bei manchen Elementen, wie zum Beispiel Buttons besteht noch die Möglichkeit eigene Skins in Form von Pixelgrafiken auf ihnen zu zeichnen, aber das bringt sehr unschöne Pixeleffekte mit sich, wenn man die Größe dieser Buttons ändert. Insbesondere bei den Applikationen, die sowohl auf iPhone 4 als auch auf früheren Modellen gleich aussehen sollen, sind solche Pixeleffekte wegen unterschiedlicher Auflösungen vorprogrammiert. Außerdem wird manchmal ein Element mit ganz besonderem Verhalten gewünscht, welches kein Standard-Element hat.

Alle diese Problemen kann man umgehen, wenn man die Vektorgrafik zu Darstellung von Steuerelementen benutzt, d.h., wenn die Elemente in dem Programm selbst "on the fly" gezeichnet werden. Dazu steht den Entwicklern für iPhone das Framework "Core Graphics" zu Verfügung, welches das Zeichnen von einfachen Geometrien (Linien, Rechtecke, Kreise, Polygone, etc.) mit Unterstützung von Farbeffekten und Transformationen ermöglicht. Die folgende Abbildung zeigt Fragment einer Statusbar, die komplett mit Mitteln der Vektorgrafik gezeichnet wird:

Hier werden zwei Arten von Steuerelementen benutzt, die in der Standardauswahl von iPhone so nicht zu finden sind: Toggle-Buttons (links im Bild) und Switches (rechts im Bild). Man sieht, dass der zweite Toggle-Button von links aktiviert ist, während die restlichen inaktiv sind und dass der rechte Switch (mit Sound-Symbol) ausgeschaltet ist. Darüber hinaus erscheinen rote Kreuze über den beiden linken Switches, um einen Fehler zu symbolisieren. Der Gradient im Hintergrund so wie leichtes Leuchteffekt auf den Toggle-Buttons sind im Übrigen auch Elemente der Vektorgrafik.

Solche grafischen Elemente sind natürlich beliebig verlustfrei skalierbar und man kann außerdem die Farben beliebig ändern und zwar zur Laufzeit: Wenn man zum Beispiel in einem Spiel für unterschiedliche Parteien spielen kann, dann kann man das Interface der Applikation, je nach dem auf wessen Seite der Benutzer spielt, farbig anpassen. In der folgenden Abbildung sind ein Toggle-Button und ein Switch vergrößert und eine Auswahl von Toggle-Buttons in vier verschiedenen Farben dargestellt:

Offensichtlich müsste man ohne die Vektorgrafik in den oberen Beispielen eine große Anzahl an Pixelgrafiken benutzen. Besonderes bei animierten Elementen erweist sich die Vektorgrafik als sehr vorteilhaft. In der folgenden Animation ist ein Switch animiert dargestellt, um zu zeigen, dass der mit ihm assoziierte Dienst (in diesem Fall GPS) aktiv ist:

Außer reinen Animationen, die einfach nur zeigen, ob etwas zur Zeit aktiv ist, besteht die Möglichkeit, mit Hilfe von der Vektorgrafik wichtige Informationen zu visualisieren. Zum Beispiel sieht man in der folgenden Animation, wie feingranular angezeigt werden kann, wie viel Prozent der Batterie verbraucht ist:

Mit Pixelgrafik würde man hier lediglich bestimmte Zustände anzeigen, wie z.B. 0%, 25%, 50%, 75%, 100% Akku-Leistung, wobei diese fünf Bilder irgendwo im Speicher abgelegt werden müssten und dann entsprechend ausgetauscht.

Je nach Fantasie kann man beliebige Indikatoren ausdenken, die wichtige Informationen veranschaulichen können. In der folgendem Video ist ein Indikator für die Ungenauigkeit von Kompass zu sehen, in welchem sich die Kompassnadel umso weiter von der vertikalen Ausrichtung wegdreht, je ungenauer der Kompass ist, wobei die Ungenauigkeit des Kompasses, die in Grad gemessen wird, dieser Drehung entspricht:

Die Vektorgrafik erlaubt auch die Pixelgrafiken zu zeichnen und insbesondere Pixelgrafiken mit Vektorgrafik zu kombinieren. In der folgenden Abbildung sieht man links eine Bitmap, die in der Mitte in einen mit Mitteln der Vektorgrafik erzeugten Button integriert ist, und rechts in eine rein "vektorgrafische" Leuchtblase:

Mit der Vektorgrafik kann man nicht nur neue Elemente implementieren, sondern auch die bestehenden ersetzen, wenn sie dem Konzept der Applikation nicht entsprechen. In der folgenden Abbildung ist dem Standard Switch (Analogon zu Checkbox) von iPhone (links), der ziemlich unbeholfen wirkt, ein alternativer mit der Vektorgrafik gemachte (rechts) gegenübergestellt:

Programmierbeispiel

Anhand von der Checkbox von oben soll im Folgenden erklärt werden, wie man eigene Steuerelemente auf iPhone implementieren kann.

Man braucht dafür eine Klasse, die von UIView oder einer ihrer Unterklassen erbt. Der Zustand der Checkbox (checked/unchecked) wird in der booleschen Instanzvariable checked gespeichert.

@interface CheckBox : UIView
{
    BOOL checked;
}
 
@property (readonly) BOOL checked;
 
@end

In der Initialisierungsmethode initWithFrame: wird zuerst festgelegt (mit der Variable singleTapGestureRecognizer), dass bei einmaligem Tippen auf der View die Instanzmethode hasBeenSingleTapped: aufgerufen wird:

@implementation CheckBox
 
@synthesize checked;
 
- (id) initWithFrame:(CGRect)rect
{
    self = [super initWithFrame:rect];	if(!self) return self;
 
    checked = YES;
 
    UITapGestureRecognizer *singleTapGestureRecognizer 
        = [[UITapGestureRecognizer alloc] initWithTarget:self
                                           action:@selector(hasBeenSingleTapped:)];
    [singleTapGestureRecognizer setNumberOfTapsRequired: 1];
    [self addGestureRecognizer:singleTapGestureRecognizer];
    [singleTapGestureRecognizer release];
 
    return self;
}
 
 
- (void) hasBeenSingleTapped:(UITapGestureRecognizer *)gestureRecognizer
{
    checked = !checked;
    [self setNeedsDisplay];
}
 
 
- (void)drawRect:(CGRect)rect
{	
    CGContextRef context = UIGraphicsGetCurrentContext();
 
    // white square
    CGContextSetRGBFillColor(context, 0.9f, 0.9f, 0.9f, 1.0f);
    CGContextFillRect(context, rect);
 
    // grey border
    CGContextSetLineWidth(context, rect.size.width/8.0f);
    CGContextSetRGBStrokeColor(context, 0.3f, 0.3f, 0.3f, 1.0);
    CGContextStrokeRect(context, rect);
 
    // checkmark
    if(checked){
        CGContextSetRGBStrokeColor(context, 0.0f, 0.0f, 0.0f, 1.0);
        CGPoint addLines[] = {
            CGPointMake(rect.size.width*0.2f,  rect.size.height*0.4f),
            CGPointMake(rect.size.width*0.45f, rect.size.height*0.7f),
            CGPointMake(rect.size.width*0.8f,  rect.size.height*0.2f),
        };
        CGContextAddLines(context, addLines, 3);
        CGContextStrokePath(context);
    }
}
 
@end

Das Zeichnen geschieht in der Methode drawRect:. Diese Methode wird automatisch aufgerufen, zuerst beim Erzeugen der View und sonst jedes Mal, sobald die View mit dem Aufruf der Methode setNeedsDisplay aufgefordert wird, sich zu erneuern, und bekommt als Parameter die Position und die Größe der View in Bildschirmkoordinaten. In dieser Methode muss man nur den graphischen Kontext UIGraphicsGetCurrentContext() beziehen und ihn zum Zeichnen benutzen. Mit Hilfe von speziellen Befehlen oder Kombinationen von Befehlen kann man viele primitive Objekte zeichnen: Linien, Rechtecke, Kreise, etc. Der Befehl CGContextFillRect(context, rect); in dem Beispiel zeichnet ein gefülltes Rechteck an der Position und in der Größe gemäß der Variable rect. Da diese Variable rect gerade der Position und Größe der ganzen View entspricht, füllt das Rechteck die ganze View aus. Wegen des Befehls CGContextSetRGBFillColor(context, 0.9f, 0.9f, 0.9f, 1.0f); ist die Füllfarbe des Rechtecks (R,G,B,A = 0.9, 0.9, 0.9, 1.0), also etwas abgedunkeltes weiß. Damit der Rahmen und das Häkchen bei unterschiedlichen Skalierungsfaktoren mit passender Linienbreite gezeichnet werden, muss diese Linienbreite in Abhängigkeit von der Größe der View gesetzt werden. CGContextSetLineWidth(context, rect.size.width/8.0f); setzt die Linienbreite auf ein Achtel der Breite der View. Mit CGContextSetRGBStrokeColor(context, 0.3f, 0.3f, 0.3f, 1.0); wird die Vordergrundfarbe auf dunkelgrau gesetzt und mit anschließendem CGContextStrokeRect(context, rect) wird ein Rechteck in dieser Farbe mit der oben definierten Linienbreite und von der Größe der View gezeichnet. Damit ist die ungecheckte Checkbox fertig und es bleibt nur noch das Häkchen zu zeichnen. Dieses Häkchen ist einfach eine gebrochene Linie mit drei Ankerpunkten, die der Inhalt des Arrays addLines sind. Mit CGContextAddLines(context, addLines, 3); werden alle drei Punkte zu dem Kontext hinzugefügt und mit Linien verbunden. Mit CGContextStrokePath(context); wird das Häkchen anschließend gezeichnet. Bei den Koordinaten der Punkte handelt es sich offensichtlich um relative Werte, die sich an die Größe der View orientieren und damit sicherstellen, dass dieses Häkchen immer maßstabsgetreu skaliert wird.


Page last modified on March 22, 2011, at 10:54 AM