Teil 2: Die Klasse MenuItem
Bevor wir an Teil 1 anknüpfen möchte ich erst auf die Hauptklasse eingehen mit der wir unser späteres Menü erstellen - die Klasse MenuItem. Folgender Grundgedanke steckt dahinter: Jeder Menüpunkt besitzt Eigenschaften wie z.B. id, title, link usw. Die Anzahl der Eigenschaften kann unterschiedlich sein - je nachdem, wie die XML-Datei aussieht. Deshalb werden diese Werte in einem Array namens _values gespeichert. Des weiteren kann jedes MenuItem weitere Untermenüpunkte haben - auch hier ist die Anzahl unbekannt. Diese Untermenüpunkte sind ebenfalls Objekte der Klasse MenuItem und werden im Array _subItems gespeichert. Unser Menü fängt also mit einem Root-MenuItem an, das selbst zwar keine Eigenschaftswerte besitzt aber sämtliche Untermenüs beinhaltet. Beispielsweise sieht das dann so aus:
Struktur:
root
_values (leer)
_subItems
level1Item
_values (title = "home", id = 1)
_subItems
level2Item
_values (title = "archiv", id = 3)
_subItems (leer)
...
level1Item
_values (title = "about", id = 2)
_subItems
...
...
Die TYPO3 Menüstruktur kann also beliebig tief sein, da jedes MenuItem wiederrum andere Items aufnehmen kann.
Abstrahierung
Man erstellt ein Flashmenü ja meist aus dem Grund, da es schick aussehen soll und möglichst viel Effekte bietet (ich mach das zumindest aus dem Grund ^^). Deshalb muss es möglich sein, Menüpunkte unterschiedlicher level (also Tiefenebenen) auch unterschiedlich darzustellen / animieren. Da die Funktionalität aber im Großen und Ganzen immer die gleiche bleibt (jeder Menüpunkt hat einen Link, kann angeklickt werden, kann bei Bedarf ausgeblendet werden usw.) bietet es sich in Flash an, diese Eigenschaften und Methoden zu vererben.
Die Klasse MenuItem dient also nur als Dummy - alle abgeleiteten Klassen z.B. level1Item, level2Item erben die vorhandenen Funktionen und erweitern die Klasse um individuelle Eigenschaften und Methoden die z.B. für Animationen zuständig sind. Wenn ihr das Vererbungsprinzip jetzt nicht auf den ersten Anhieb verstanden habt, dann macht euch nichts daraus - wir kommen später nochmal genauer darauf zu sprechen.
Der ActionScript Code
Der Code der ActionScript Klasse wird in einer externen AS-Datei gespeichert - diese Datei sollte sich im gleichen Verzeichnis wie die *.fla Datei befinden und genau so heißen wie die Klasse selbst. In unserem Fall also menuItem.as. Ich habe versucht, alles möglichst genau zu kommentieren.
So sieht der AS-Code aus:
/*
* Class MenuItem:
* Klasse zur Ableitung der MenüItems für alle Level
* Thomas Raithel 2007 - www.mortox.de
*/
class MenuItem {
// Eltern menuItem falls vorhanden
private var _parent :MenuItem = null;
// Werte wie z.B. id, link, title usw.
private var _values :Array;
// Weitere Untermenüpunkte vom Typ MenuItem
private var _subItems :Array;
public var _position :Number; //(z.B. 0 = Erster Menüpunkt usw.)
//Pointer zum MovieClip, wenn das item mit draw() erstellt wurde
public var _mc :MovieClip;
//Konstruktor - Übergabewert sind die Eigenschaften + Menüposition
public function MenuItem(values :Array, position :Number) {
this._values = values;
this._position = position;
this._subItems = new Array();
}
//Fügt ein neues Item zu den Subitems
public function addItem(item :MenuItem) :Void {
item._parent = this; //aktuelles Item ist parent
this._subItems.push(item);
}
//Erstellt die Movieclips der Menüpunkte auf der Bühne
//Sind von den Kindklassen zu überschreiben - sonst keine Ausgabe!
public function draw() :Void {
//Subitems zeichnen
for(var i:String in this._subItems) {
this._subItems[i].draw();
}
//Standardevents zuweisen
this.attachEvents();
}
//Initialisiert das Menü mit einem Menüpunkt
//Ist von den Kindklassen zu überschreiben
public function init(id :Number) :Void {
for(var i:String in this._subItems) {
this._subItems[i].init(id);
}
}
//Prüft ob die übergebene Id dieses Item ist oder unterhalb liegt
private function hasIdOrSub(id :Number) :Boolean {
trace(this._values["uid"]);
if(this._values["uid"] == id)
return true;
for(var i:String in this._subItems) {
if(this._subItems[i].hasIdOrSub(id))
return true;
}
return false;
}
//Interne Funktion, die dem Button-MC die Events zuweist
private function attachEvents() {
if(this._mc != null) {
//Verknüpfung zu diesem Objekt anlegen
this._mc.itemObject = this;
this._mc.onPress = function () {
this.itemObject.press();
};
this._mc.onRollOver = function () {
this.itemObject.rollOver();
};
this._mc.onRollOut = function () {
this.itemObject.rollOut();
};
this._mc.onEnterFrame = function () {
this.itemObject.enterFrame();
};
}
}
private function press() :Void {
//von Kindklasse zu setzen
}
private function rollOver() :Void {
//von Kindklasse zu setzen
}
private function rollOut() :Void {
//von Kindklasse zu setzen
}
private function enterFrame() :Void {
//von Kindklasse zu setzen
}
//ruft die display()-Methode aller Subitems auf
private function displaySubItems() {
for(var i:String in this._subItems) {
this._subItems[i].display();
}
}
//ruft die hide()-Methode aller Subitems auf
private function hideSubItems() {
for(var i:String in this._subItems) {
this._subItems[i].hide();
}
}
private function display() :Void {
//von Kindklasse zu setzen
}
private function hide() :Void {
//von Kindklasse zu setzen
}
//Gibt die XML-Struktur aus (zu Testzwecken)
public function testTrace() :Void {
//Gibt den Inhalt des Arrays aus
for(var i:String in this._values) {
trace(i + " => " + this._values[i]);
}
for(var i:String in this._subItems) {
this._subItems[i].testTrace();
}
}
}
Erklärungen
Der Konstruktor nimmt die Eigenschaftswerte (_values) in Form eines Arrays und die Position des Menüpunktes in Form einer Zahl (0 bis X) entgegen. Diese Zahl _position ist später beim "zeichnen" des Menüs wichtig. Mit der Methode addItem() werden die _subItems befüllt. Jedes SubItem besitzt außerdem ein _parent - also einen Zeiger auf den Elternknoten mit dessen Hilfe man auf die Überpunkte zurückgreifen kann. Die draw() Methode erstellt einen MovieClip auf der Bühne der den Menüpunkt repräsentiert. Diese muss von den abgeleiteten Klassen beschrieben werden. Mittels init() wird eine Seiten-ID übergeben - somit weiß das Menü zu Beginn, welches Item aktiv ist. hasIdOrSub() gibt true zurück, wenn der Menüpunkt die übergebene ID hat oder einer seiner SubItems. attachEvents() weißt dem vorhandenen _mc (also der sichtbare Button) eine Reihe von wichtigen Events zu. Diese Events sind Methoden unserer Klasse und reagieren auf unterschiedliche Ereignisse:
- press() - der Button wird geklickt
- rollOver() - die Maus rollt über den _mc
- rollOut() - verlassen des _mc mit der Maus
- enterFrame() - wird bei jedem neuen Frame aufgerufen
Diese 4 genannten Methoden und die draw() Methode sind die wichtigsten Funktionen die geändert werden müssen, wenn eine neue Menüebene erstellt werden muss!
hide() und display() sind Funktionen die aufgerufen werden wenn der Menüpunkt verschwinden / erscheinen soll - hideSubItems() und displaySubItems() verfahren dementsprechend mit allen Unterpunkten.
Die testTrace() Methode gibt alle gespeicherten Werte auf der Konsole aus - dies dient zum Testen ob das Auslesen der XML-Datei auch geklappt hat.
In der Regel sind diese Funktionen ausreichend für das Grundgerüst einer Menge unterschiedlicher Flashmenüs. Diese Klasse selbst sollte nicht verändert werden - stattdessen werden die Funktionen in den abgeleiteten Klassen manipuliert, erweitert oder komplett neue Methoden hinzugefügt.















