AS3 101: Ereignisse - Basix
German (Deutsch) translation by Federicco Ancie (you can also view the original English article)
In diesem Kapitel von AS3 101 werden wir in die Mechanik des Flash-Ereignissystems eintauchen. Wenn Sie bisher mitverfolgt haben, haben Sie Ereignisse im Einsatz gesehen, die bis in die erste Episode der Serie zurückreichen. Der Redakteur und ich waren der Meinung, dass es an der Zeit war, etwas zu schreiben, das offiziell in den Lehrplan aufgenommen werden sollte Tutorial für Sie.
Es gibt bereits ein Activetuts+-Tutorial zu den Grundlagen von Events, daher liegt der Schwerpunkt dieses Tutorials auf dem Dispatching von Events aus Ihren eigenen Klassen, einschließlich der Erstellung benutzerdefinierter Event-Typen und -Objekte.
Um mit diesem Tutorial erfolgreich zu sein, sollten Sie mit dem Schreiben und Verwenden Ihrer eigenen Klassen in ActionScript 3 vertraut sein und sich mit der Verwendung der vorhandenen Flash-Ereignisse wie MouseEvent.CLICK
oder Event.ENTER_FRAME
sicher fühlen. Wir werden uns in erster Linie darauf konzentrieren, benutzerdefinierte Ereignisse aus benutzerdefinierten Klassen zu versenden.
Vorschau
Wir werden für dieses Tutorial viel Zeit mit der Theorie verbringen, aber am Ende bauen wir ein einfaches Schieberegler-Steuerelement, das seine eigenen Ereignisse auslöst:
Schritt 1: Warum Event-Dispatching verwenden?
Dieses Beispiel ist eigentlich ein ziemlich einfaches Beispiel dafür, warum Sie Ihre eigenen Ereignisse versenden möchten. Wenn Sie Ihre eigenen Klassen schreiben, halten Sie sie idealerweise in ihren eigenen Blackboxen und gekapselt. Aber Sie müssen immer noch die verschiedenen Objekte zusammenarbeiten lassen, um ein nützliches Programm zu erstellen.
Das von ActionScript 3 bereitgestellte Ereignismodell ist eine ziemlich gute und bequeme Möglichkeit, die Kommunikation zwischen Ihren Klassen zu erleichtern und gleichzeitig die Zuständigkeiten in Ihren Klassen zu trennen. Wenn wir also unsere eigene benutzerdefinierte Klasse schreiben, wie die oben gezeigte ActiveSlider
-Klasse, müssen wir anderen Objekten ermöglichen, sich bewusst zu machen, wenn der Slider seinen Wert ändert. Wenn der Schieberegler sein eigenes Änderungsereignis senden kann, können andere Objekte, die diese Informationen kennen müssen, problemlos abonnieren und benachrichtigt werden.
Ich persönlich finde die Notwendigkeit, meine eigenen Ereignisse in meinen Klassen zu verteilen, so häufig, dass meine Klassenvorlage jede neue Klasse mit der dafür notwendigen Boilerplate einrichtet. Wenn Sie lernen, Objekte diskret zu halten, wenden Sie sich dem Ereignis-Dispatching als der gebräuchlichsten Methode zu.
Schritt 2: So versenden Sie Ihre eigenen Events
Ich habe gute Nachrichten: Das Versenden eigener Events ist eigentlich ganz einfach. Dies ist einer der Kernpunkte von ActionScript 3, der in den Flash Player integriert ist, und als solcher müssen Sie nur eines tun, um die Fähigkeit zum Versenden von Ereignissen zu erlangen. Diese eine Sache ist:
EventDispatcher
erweitern
Das war's: Verwenden Sie beim Schreiben Ihrer Klasse die Zeile:
public class MyClass extends EventDispatcher {
Natürlich müssen Sie EventDispatcher
importieren, der sich im flash.events
-Paket befindet. Sie werden wahrscheinlich andere Klassen im Paket benötigen, daher ist es möglicherweise am bequemsten, das Paket einfach mit einem Platzhalter zu importieren.
import flash.events.*;
Schritt 3: Versand
Jetzt sind Sie zum Versenden eines Ereignisses eingerichtet. Jetzt müssen Sie nur noch eine von EventDispatcher
bereitgestellte Methode namens "dispatchEvent
" aufrufen. Leicht zu greifen, nicht wahr?
Wenn Sie dispatchEvent
aufrufen, müssen Sie mindestens ein Argument bereitstellen, ein Event
-Objekt. Alle integrierten Event
-Objekte befinden sich im flash.events
-Paket, daher ist der Wildcard-Import hier praktisch. Jeder Event
-Objekttyp hat seine eigenen Anforderungen, aber meistens müssen Sie ihm auch nur ein Argument übergeben. Dieses Argument ist der Ereignistyp, bei dem es sich um einen String
handelt, der das Ereignis benennt, z. B. "click"
oder "complete"
. Diese werden häufiger als MouseEvent.CLICK
oder Event.COMPLETE
geschrieben, aber das Endergebnis ist dasselbe; Es ist ein Bezeichner, der einen Ereignistyp von einem anderen trennt und es einem Event
-Objekt ermöglicht, mehrere Ereignistypen zu verwalten.
Wenn Sie also alles zusammenfassen, wenn Sie ein "complete"
Ereignis versenden möchten, können Sie dies wie folgt tun:
dispatchEvent(new Event(Event.COMPLETE));
Ziehen Sie diese Zeile (oder eine ähnliche) einfach in die Methode, die in Ihrer Klasse geeignet ist. Ihre Klasse verwendet dann ihr geerbtes Event-Dispatching-System und alle Listener werden für Sie benachrichtigt. Apropos Hörer, werfen wir auch einen kurzen Blick auf diese.
Schritt 4: Hören Sie zu
Jedes andere Objekt in Ihrer Anwendung kann jetzt auf Ihre benutzerdefinierten Ereignisse warten. Eine weitere gute Nachricht: Dies ist nicht anders als die Anmeldung zu Veranstaltungen für die integrierten Klassen. Im vorherigen Schritt haben wir unsere hypothetische Klasse eingerichtet, um ein COMPLETE
-Ereignis auszulösen. Um auf dieses Ereignis zu hören, könnten wir diese Zeile an anderer Stelle in unserem Programm schreiben:
var myObject:MyClass = new MyClass(); myObject.addEventListener(Event.COMPLETE, myCompleteHandler); function myCompleteHandler(e:Event):void { trace("My object completes me."); }
Und das ist es. Dies sollte jedem bekannt vorkommen, der zum Beispiel einen COMPLETE
-Listener mit einem Loader
verbunden hat, daher werde ich hier nicht weiter darauf eingehen.
Schritt 5: Wohin zu versenden
Wo Sie die Codezeile "dispatchEvent
" tatsächlich platzieren, erfordert einige Überlegungen. Normalerweise sollte es die letzte Codezeile der Methode sein, in der es geschrieben wird. Auf diese Weise kann jeder andere Code, der ebenfalls in dieser Methode ausgeführt wird, Eigenschaften festlegen oder den internen Zustand des Objekts auf andere Weise aktualisieren. Durch den Versand nach Abschluss dieser internen Aktualisierung befindet sich das Objekt zum Zeitpunkt des Versands in einem "sauberen" Zustand.
Betrachten Sie zum Beispiel unser Arbeitsbeispiel. Nehmen wir an, beim COMPLETE
-Ereignis dreht sich alles um die Verarbeitung einiger Daten; eine Menge von Daten, die so groß ist, dass die vollständige Verarbeitung mehrere Sekunden dauert. Der Zweck des Objekts besteht also darin, die Verarbeitung asynchron zu verarbeiten, um die Benutzeroberfläche nicht zu blockieren. Und wir senden das COMPLETE
-Ereignis, um zu sagen, dass die Daten verarbeitet wurden.
Nehmen wir nun an, dass die fragliche Hauptmethode ungefähr so aussieht:
private function processDataChunk():void { _data += someDataProcess(); if (done()) { closeData(); } }
OK, nicht sehr realistisch, aber es veranschaulicht den Punkt. Wir bauen die internen Daten so lange auf, bis eine andere interne Logik feststellt, dass wir fertig sind, und schreiben dann einige letzte Datenbits aus, um die Operation abzuschließen.
Fügen wir nun den Aufruf von "dispatchEvent
" hinzu:
private function processDataChunk():void { _data += someDataProcess(); if (done()) { dispatchEvent(new Event(Event.COMPLETE)); closeData(); } }
Was ist das Problem bei diesem Ansatz? Jeder Code, der innerhalb von Listenern für das COMPLETE
-Ereignis ausgeführt wird, wird ausgeführt, bevor die Methode closeData
aufgerufen wird. Daher ändert sich der Status des Dispatchers innerhalb der Spanne der processDataChunk
-Methode mehr als einmal und ist erst nach dem closeData
-Aufruf "stabil". Dennoch sagen wir allen unseren Zuhörern, dass wir vor diesem Anruf fertig sind. Dies könnte zu einigen schwer aufzuspürenden Fehlern führen, bei denen ein Objekt behauptet, COMPLETE
zu sein, es aber nicht ist. Die naheliegende Lösung besteht darin, einige Zeilen umzudrehen:
private function processDataChunk():void { _data += someDataProcess(); if (done()) { closeData(); dispatchEvent(new Event(Event.COMPLETE)); } }
Schritt 6: Benutzerdefinierte Ereignisse
Sie sind bereit, Ihre eigenen Ereignisse zu versenden. Was sollten Sie nun versenden? Es gibt einige Optionen, die in Betracht gezogen werden sollten:
- Verwenden Sie einfach ein Ereignisobjekt und einen Ereignistyp, die bereits vom Flash Player bereitgestellt wurden
- Wiederverwendung eines vorhandenen Ereignisobjekts, aber Bereitstellung eines benutzerdefinierten Ereignistyps
- Eine bestehende Veranstaltung erneut versenden
- Erstellen Sie ein benutzerdefiniertes Ereignisobjekt
- Drücken vs. ziehen
Diese erste Option haben wir bereits in unseren vorherigen Beispielen gesehen. Wir müssen ein Ereignis absetzen, das sich auf den Abschluss eines Prozesses bezieht, und zufällig bietet Flash einen Ereignistyp (COMPLETE
), der mit einem Ereignisobjekt (Event
) verknüpft ist, das unseren Kriterien entspricht. Wir sind nicht verpflichtet, zusätzliche Daten mit der Veranstaltung zur Verfügung zu stellen. Das Aussenden eines Event.COMPLETE
-Ereignisses ist alles, was wir brauchen.
Wir werden diese anderen Optionen in den nächsten Schritten untersuchen.
Schritt 7: Benutzerdefinierte Ereignistypen
Wie bereits im Schritt "Versand" angedeutet, handelt es sich bei Ereignistypen einfach um String
-Folgenbezeichner. Sie können technisch gesehen jeder beliebige String
sein. Normalerweise reicht es aus, daraus ein einzelnes Wort (wie "complete" oder "click") oder eine sehr kurze Phrase (wie "ioError" oder "keyFocusChange") zu machen; es muss nur innerhalb des Bereichs der verfügbaren Ereignisse eines bestimmten Ereignis-Dispatchers eindeutig sein.
Außerdem ist es Event
-Objekten (einschließlich Unterklassen wie MouseEvent
oder ProgressEvent
) egal, welchen Ereignistyp sie bei der Instanziierung erhalten. Ein EventDispatcher
sendet gerne Ereignisse von jedem Typbezeichner und jeder Klasse (sofern es die Event
-Klasse oder eine Unterklasse ist).
Das Ergebnis davon ist, dass Sie Ihren eigenen Ereignistyp String
erstellen, versenden und Listener damit einrichten können, und alles wird gut. Dies ist hilfreich, wenn Sie ein Ereignis auslösen möchten, aber nicht unbedingt eine gute Darstellung der Art des Ereignisses in den integrierten Klassen finden können.
Als Beispiel könnten Sie eine Klasse haben, die als Koordinator für mehrere Dinge gleichzeitig fungiert: XML laden, einige Bilder basierend auf den XML-Daten laden und ein Layout basierend auf den Größen der geladenen Bilder erstellen, bereit für eine erste Animation , an welcher Stelle Sie ein Ereignis versenden möchten. Während das COMPLETE
-Ereignis geeignet sein könnte, können Sie das Gefühl haben, dass ein "bereites" Ereignis die Bedeutung angemessener kapselt.
Dies ist so einfach wie sich für den zu verwendenden String
zu entscheiden und ihn dann zu verwenden. Verwenden Sie es sowohl beim Hinzufügen von Listenern als auch beim Versenden des Ereignisses. Wenn der String
übereinstimmt, wird das Ereignis dorthin gelangen, wo es hin soll. Dies ist beispielsweise eine teilweise Auflistung einer hypothetischen Klasse:
public class MyClass extends EventDispatcher { // ... A bunch of other stuff not shown. private function determineReadiness():void { if (everythingIsReady) { dispatchEvent(new Event("ready")); } } }
Und Code von woanders im selben Programm:
var myObject:MyClass = new MyClass(); myObject.addEventListener("ready", onObjectReady); function onObjectReady(e:Event):void { // Do stuff now that it's ready. }
Und das würde funktionieren.
Es ist jedoch erwähnenswert, dass es keine gute Praxis ist, überall übereinstimmende Strings
einzugeben. Die Fehlerwahrscheinlichkeit ist hoch, und das Ereignissystem teilt Ihnen nicht mit, dass Sie "raedy"
anstelle von "ready"
eingegeben haben. Die Tatsache, dass das Ereignissystem flexibel und einfach zu bedienen ist - übergeben Sie ihm einfach einen beliebigen alten String
für den Ereignistyp - ist auch eine Schwäche. Ihr Disponent akzeptiert gerne einen Listener für alles, auch für ein "raedy"
-Ereignis. Es stimmt nicht wirklich ab, welche Ereignistypen mit welchen Ereignistypen tatsächlich gesendet werden.
Um dies zu verhindern, besteht der Standardansatz darin, den String
, den Sie verwenden möchten, einfach irgendwo in eine statische Konstante einzufügen und diesen literalen String
dann nie wieder zu verwenden. Verwenden Sie nur die Konstante. Natürlich ist die Möglichkeit von Tippfehlern nach wie vor groß, aber wenn Sie eine READY
-Konstante und nicht das "ready"
-Literal String
verwenden, löst ein Tippfehler eine Compiler-Warnung aus. Sie können Ihren Fehler schnell und einfach beheben. Ein falscher Typ mit dem Literal Strings
erzeugt weder einen Compilerfehler noch einen Laufzeitfehler. Das einzige, was passiert, ist, dass die SWF-Datei nicht richtig zu funktionieren scheint, weil der Ereignis-Listener nicht ausgelöst wird.
Aus diesem Grund werden diese Konstanten am häufigsten in der zugehörigen Event
-Klasse gespeichert. In wenigen Schritten gelangen wir zu benutzerdefinierten Event
-Klassen. Aber in der in diesem Schritt beschriebenen Situation (d. h. wir verwenden eine Event
-Klasse wieder, aber keinen Ereignistyp), finde ich es bequemer, diese Konstante einfach in der Dispatcher-Klasse zu speichern. Wir könnten uns also dafür entscheiden, dies zu tun:
public class MyClass extends EventDispatcher { public static const READY:String = "ready"; // etc. private function determineReadiness():void { if (everythingIsReady) { dispatchEvent(new Event(READY)); } } }
Und:
var myObject:MyClass = new MyClass(); myObject.addEventListener(READY, onObjectReady); function onObjectReady(e:Event):void { // Do stuff now that it's ready. }
Dies gibt uns die Sicherheit, Ereignistypen in Konstanten zu speichern, ohne die Unannehmlichkeiten zu erzwingen, eine ganze Event
-Klasse zu erstellen, die wir nicht benötigen. Ich muss betonen, dass dies eine stilistische Entscheidung ist, und Sie können diese Technik gerne verwenden oder nicht. Ich war der Meinung, dass es eine Erklärung rechtfertigt, damit Sie Ihre eigene informierte Entscheidung treffen können. In beiden Fällen sollten Sie Ihre benutzerdefinierten Ereignistyp-Strings
auf jeden Fall in statischen Konstanten speichern. Wo diese statischen Konstanten definiert werden, liegt bei Ihnen.
Schritt 8: Erneutes Versenden von Ereignissen
Es gibt mehrere Fälle, in denen eine Klasse (nennen wir sie ClassX
) eine Eigenschaft besitzt, die als eine andere Klasse typisiert ist (wir nennen sie ClassY
), während sie selbst einer dritten Klasse gehört (wie wäre es mit ClassZ
?). ClassX
lauscht auf ein Ereignis von ClassY
, aber wir möchten nicht nur, dass ClassX
auf das Ereignis reagiert, wir möchten auch berücksichtigen, dass ClassX
ein ähnliches (oder sogar dasselbe) Ereignis aussenden sollte, damit ClassZ
auch weitere Maßnahmen ergreifen kann.
Als konkreteres Beispiel haben wir eine Klasse (dies wird "ClassX
" sein), die eine Art Datenmanager ist. Es lädt ein XML-Dokument, analysiert es und speichert Daten aus dem XML in seinen eigenen Eigenschaften. Es hat also ein URLLoader
-Objekt (dies wäre "ClassY
") und wartet auf das Event.COMPLETE
-Ereignis, wenn das XML-Dokument geladen wird.
Dann haben wir eine Hauptdokumentklasse, die den Datenmanager besitzt (die Dokumentklasse ist "ClassZ
"). Es koordiniert das Laden der Daten mit anderen UI-Elementen, möchte also wissen, wann die Daten geladen und bereit sind, damit es UI-Elemente basierend auf den Daten erstellen und gestalten kann.
public class DataManager extends EventDispatcher { private var _xmlLoader:URLLoader; public function DataManager() { _xmlLoader = new URLLoader(new URLRequest("some.xml")); _xmlLoader.addEventListener(Event.COMPLETE, onLoadComplete); } // ... A bunch of other stuff private function onLoadComplete(e:Event):void { // ... XML parsing // With the XML parsed, we'd like to dispatch another event to signal being done. } }
Wir könnten dies tun:
dispatchEvent(new Event(Event.COMPLETE));
Aber wir könnten auch dies tun:
dispatchEvent(e);
Hier versenden wir einfach die bestehende Veranstaltung neu. Wir verwenden nicht nur den Ereignistyp und die Event
-Klasse wieder, sondern verwenden tatsächlich das gesamte Event
-Objekt, wie es an unseren eigenen Listener übergeben wurde.
Es ist keine Raketenwissenschaft, aber es ist eine praktische kleine Technik, die überraschenderweise nicht so offensichtlich ist.
"Aber warten Sie", müssen Sie denken, "wenn wir ein Ereignis, das vom URLLoader
-Objekt stammt, erneut versenden würden, wäre das target
des Ereignisses dann nicht immer noch _xmlLoader
, wenn es wieder in die Dokumentenklasse zurückkehrt?" Und Sie hätten einen sehr guten und nachdenklichen Punkt, und ich wäre stolz auf Sie, dass Sie so fleißig nachdenken, aber Sie würden sich irren.
Beim Redispatching von Ereignissen passiert etwas Magisches. Die target
-Eigenschaft wird auf den aktuellen Dispatcher festgelegt. Ein funktionierendes Beispiel für den Code in diesem Schritt finden Sie im Downloadpaket mit dem Titel redispatch.
Eigentlich ist es gar nicht so magisch. Wenn beim Aufrufen von "dispatchEvent
" das übergebene Event
-Objekt bereits ein target
hat, wird die clone
-Methode für das Event
aufgerufen, wodurch eine identische, aber diskrete Kopie des ursprünglichen Event
erstellt wird, mit Ausnahme des in target
enthaltenen Werts.
Schritt 9: Benutzerdefinierte Ereignisobjekte
Alles, was bisher erwähnt wurde, ist etwas, das Sie wissen wollen. Aber es wird einen Punkt geben, an dem es am besten ist, Ihr eigenes benutzerdefiniertes Ereignis zu versenden. Nicht nur ein benutzerdefinierter Ereignistyp, sondern eine ganze benutzerdefinierte Event
-Klasse.
Der Prozess dafür ist einfach, Sie müssen nur ein paar Schritte befolgen. Wir werden diese zu gegebener Zeit besprechen. Beachten Sie, dass ein Großteil davon Boilerplate-Code ist, und Sie könnten leicht eine Vorlage für eine Event
-Unterklasse erstellen und nur ein paar Schlüsselelemente ändern und loslegen. Die allgemeinen Schritte in verkürzter-als-ob-du-wussten-wovon-ich-sprach:
- Unterklasse-
Event
- Rufen Sie
super(...)
- Ereignistypen in öffentlichen statischen Konstanten speichern
- Deklarieren Sie private Eigenschaften, um benutzerdefinierte Daten zu speichern
- Erstellen Sie öffentliche Getter, um schreibgeschützten Zugriff auf die benutzerdefinierten Informationen zu ermöglichen
- (Optional) Überschreiben Sie die
clone
-Methode - (Optional) Überschreiben Sie die
toString
-Methode
Um diesen Prozess genauer zu erklären, beginnen wir mit unserem Slider-Projekt und erstellen das SliderEvent
, das wir dafür benötigen. Wir müssen also unser Projekt starten, bevor wir etwas Code schreiben können, also eine kurze Umleitung im nächsten Schritt, dann beginnen wir mit dem Schreiben einer benutzerdefinierten Event-
Klasse.
Schritt 10: Erstellen Sie die Projektstruktur
Wir halten die Dinge hier ziemlich einfach, aber wir werden trotzdem Pakete für unsere Klassen erstellen.
Erstellen Sie zunächst einen Ordner für das gesamte Projekt. Meins wird Slider heißen.
Erstellen Sie darin einen com-Ordner und darin einen activetuts-Ordner.
Erstellen Sie nun zwei Ordner innerhalb von activetuts: events und ui. Ihre endgültige Ordnerstruktur sollte in etwa so aussehen:
- slider
- com
- activetuts
- events
- slider
- activetuts
- com
Nun zurück zu unserer Event
-Klasse.
Schritt 11: Event
-Unterklassen
Erstellen Sie zunächst eine neue Textdatei im Ordner slider/com/activetuts/events und nennen Sie sie SliderEvent.as. Wir werden zuerst die Boilerplate für jede Klasse einfügen:
package com.activetuts.events { public class SliderEvent { public function SliderEvent() { } } }
Hier sollte es nichts Überraschendes geben, und wenn Sie ActionScript-Vorlagen für Ihren Texteditor haben, sollten Sie nicht einmal so viel eingeben müssen.
Jetzt ändern wir dies so, dass es Event
erweitert.
package com.activetuts.events { import flash.events.Event; public class SliderEvent extends Event { public function SliderEvent() { } } }
Wie Sie sehen, importieren wir einfach die Event
-Klasse, fügen Sie extends Event
zur Klassendefinition hinzu.
Schritt 12: super
anrufen
Unsere Superklasse kann viel für uns erledigen, was großartig ist, aber wir müssen sicherstellen, dass wir die Superklasse richtig initialisieren, wenn wir unsere Unterklasse initialisieren. Wir müssen den Konstruktor mit Argumenten einrichten, die denen im Konstruktor von Event
entsprechen, und diese zusammen mit einem Aufruf an super
übergeben.
package com.activetuts.events { import flash.events.Event; public class SliderEvent extends Event { public function SliderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true) { super(type, bubbles, cancelable); } } }
Dies sind bisher grundlegende Unterklassentechniken. Abhängig von den Fähigkeiten Ihres Editors mit Vorlagen können Sie sogar eine Superklasse angeben, wenn Sie die Datei erstellen, und dies alles für Sie erledigen lassen. Flash Builder ist zum Beispiel in der Lage, dies zu tun.
Schritt 13: Speichern Sie Ereignistypen in öffentlichen statischen Konstanten
Vermutlich sind dieser Ereignisklasse ein oder mehrere Ereignistypen zugeordnet. Genauso wie das COMPLETE
-Ereignis der Event
-Klasse und das CLICK
sogar der MouseEvent
-Klasse zugeordnet ist, wird unsere benutzerdefinierte Ereignisklasse wahrscheinlich benutzerdefinierte Ereignistypen haben.
Dies ist so einfach wie das Schreiben einer Zeile wie der folgenden für jeden Ereignistyp, den Sie hinzufügen möchten:
public static const EVENT_TYPE:String = "eventType";
Machen wir das jetzt für die SliderEvent
-Klasse.
package com.activetuts.events { import flash.events.Event; public class SliderEvent extends Event { public static const CHANGE:String = "sliderChange"; public function SliderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true) { super(type, bubbles, cancelable); } } }
Wir könnten unsere Klasse jetzt theoretisch gebrauchen. Wir können das SliderEvent
in dispatchEvent
verwenden und Ereignisse mit dem SliderEvent.CHANGE
-Ereignistyp abhören und erstellen.
Aber wir werden hier nicht aufhören. Es gibt mehr zu beachten. Aber bevor wir mehr Code schreiben, müssen wir noch einen Abstecher in die Theorie machen.
Schritt 14: Push vs. Pull
Wenn ein Ereignis ausgelöst wird, reicht es manchmal aus, einfach zu wissen, dass das Ereignis eingetreten ist. Wenn Sie beispielsweise an Event.ENTER_FRAME
-, Event.COMPLETE
- oder TimeEvent.TIMER
-Ereignissen interessiert sind, möchten Sie wahrscheinlich nur wissen, dass das Ereignis stattgefunden hat. Es gibt jedoch andere Zeiten, in denen Sie wahrscheinlich mehr wissen möchten. Beim Anhören von MouseEvent.CLICK
interessiert Sie möglicherweise, ob die Umschalttaste gedrückt gehalten wurde, oder die Koordinaten der Maus zum Zeitpunkt des Klickens. Wenn Sie sich ProgressEvent.PROGRESS
anhören, möchten Sie wahrscheinlich den tatsächlichen Fortschritt des Ladevorgangs wissen. das heißt, wie viele Bytes geladen wurden und wie viele insgesamt geladen werden sollen.
Der Unterschied zwischen diesen beiden Methoden wird manchmal als "Push" und "Pull" bezeichnet. Diese Begriffe beziehen sich darauf, wie der Ereignis-Listener Daten in Bezug auf das Ereignis abruft. Wenn die Daten "gepusht" werden, werden Daten im Ereignisobjekt gespeichert, und um die Daten abzurufen, muss der Listener lediglich Eigenschaften des Ereignisobjekts verwenden. Sollen jedoch Daten "gezogen" werden, enthält das Event-Objekt in der Regel nur sehr wenige Informationen - nur das Nötigste: den Typ, das Ziel usw. Dieses Ziel ist jedoch unverzichtbar, da es den Zugriff auf den Event-Dispatcher ermöglicht an den Ereignis-Listener, sodass der Listener die benötigten Daten vom Dispatcher abrufen kann.
Mit anderen Worten, Sie können entweder eine Reihe von Daten an den Listener innerhalb des Ereignisobjekts pushen oder den Listener auffordern, die Daten nach Bedarf aus dem Dispatcher zu ziehen.
Die Vor- und Nachteile der einzelnen Techniken sind meiner Meinung nach etwas ausgewogen und der Weg, den Sie für Ihr Veranstaltungsobjekt wählen, hängt von der jeweiligen Situation und nicht von persönlichen Vorlieben ab.
Ausstellung A:
Vorteile | Nachteile | |
---|---|---|
Drücken |
|
|
Ziehen |
|
|
Dies könnte eine gute Diskussion für die Kommentare sein; Ich bin sicher, dass viele von Ihnen, die lesen, eine leidenschaftliche Meinung darüber haben, welche Methode die bessere ist. Persönlich versuche ich, die Methode zu finden, die für die Situation am besten funktioniert.
Trotzdem ist es erwähnenswert, dass unsere SliderEvent
-Klasse bis jetzt eher "Pull-ish" ist. Zur Veranschaulichung und weil es keine schlechte Idee ist (obwohl ich mir einige davon ausgedacht habe), werden wir dies zu einem Ereignis machen, das Daten mit sich bringt. nämlich der Wert des Schiebereglers, wenn er geändert wurde.
Schritt 15: Deklarieren privater Eigenschaften zum Enthalten benutzerdefinierter Daten
Um ein Push-Ereignis zu implementieren, benötigen wir einen Ort zum Speichern der gepushten Daten. Zu diesem Zweck fügen wir eine private Eigenschaft hinzu.
Sie sollten SliderEvent
immer noch geöffnet haben (wenn nicht... worauf warten Sie noch?). Fügen Sie die markierte Zeile hinzu:
package com.activetuts.events { import flash.events.Event; public class SliderEvent extends Event { public static const CHANGE:String = "sliderChange"; private var _sliderValue:Number; public function SliderEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true) { super(type, bubbles, cancelable); } } }
Als nächstes ändern wir den Konstruktor so, dass wir einen Wertparameter akzeptieren können, und legen die private Eigenschaft damit fest:
public function SliderEvent(type:String, sliderValue:Number, bubbles:Boolean=false, cancelable:Boolean=true) { _sliderValue = sliderValue; super(type, bubbles, cancelable); }
Auf diese Weise können wir das SliderEvent
einfach erstellen und seine Push-Daten in einer Zeile einrichten.
Warum private Immobilien nutzen? In diesem Fall möchten wir die Daten schützen. Meiner Meinung nach sind die Daten zu einem Ereignis unveränderlich, solange sie mit dem Ereignis verknüpft sind. In der Lage zu sein, die Daten eines Ereignisobjekts zu ändern, ist wie das Bearbeiten eines Geschichtslehrbuchs. Um fair zu sein, dies ist meine Meinung und der von Adobe mit seinen integrierten Klassen verwendete Standard besteht darin, beschreibbare Eigenschaften zu verwenden (technisch gesehen verwenden sie private Eigenschaften und öffentliche Getter und Setter, aber das Endergebnis ist das gleiche).
Schritt 16: Erstellen Sie öffentliche Getter für die benutzerdefinierten Daten
Der nächste Schritt wäre also, sicherzustellen, dass wir auf die übertragenen Daten zugreifen können. Ein privates Eigentum allein ist für diesen Zweck nicht nützlich. Daher müssen wir einen öffentlichen Getter für die Eigenschaft _sliderValue
schreiben. Wir werden uns dafür entscheiden, keinen Setter zu schreiben, damit die Eigenschaft schreibgeschützt wird (wie im letzten Schritt besprochen).
Fügen Sie diese Methode der Klasse hinzu:
public function get sliderValue():Number { return _sliderValue; }
Dadurch wird ein Getter hinzugefügt, sodass wir auf den sliderValue
auf eine Eigenschafts-ähnliche Weise zugreifen können. Ich entscheide mich, den passenden Setter nicht hinzuzufügen. Sie können einen hinzufügen, wenn Sie der Meinung sind, dass es sich lohnt.
Schritt 17: Überschreiben Sie die clone
-Methode
Ich habe vor einiger Zeit die clone
-Methode erwähnt. Sie werden wahrscheinlich selbst nicht oft clone
, aber es ist keine schlechte Idee, die clone
-Methode zu überschreiben, damit Ihr benutzerdefiniertes Ereignis gut mit dem Ereignissystem zusammenspielt.
Fügen Sie diese Methode zu Ihrer Klasse hinzu:
override public function clone():Event { return new SliderEvent(type, sliderValue, bubbles, cancelable); }
Beachten Sie zunächst die Signatur dieser Methode. Wir verwenden override
, weil diese Methode in Event
deklariert ist und wir sie erben. Es gibt auch ein Objekt vom Typ Event
zurück. Stellen Sie beim Schreiben Ihrer clone
-Uberschreibung sicher, dass Sie den richtigen Rückgabetyp eingeben. Es ist leicht zu vergessen und den Typ Ihrer Klasse dort einzufügen, aber das führt zu einem inkompatiblen Überschreibungsfehler, da die Rückgabetypen übereinstimmen müssen.
Alles, was wir im Kern des Events wirklich tun, ist, ein neues SliderEvent
zu erstellen und die gleichen Werte zu übergeben, die wir im aktuellen Event-Objekt gespeichert haben. Dadurch entsteht eine identische, aber diskrete Kopie: ein Klon.
Dies ist ein optionaler Schritt, aber es ist ein schneller Erfolg und stellt sicher, dass Ihr benutzerdefiniertes Event gut mit dem Rest des Eventsystems zusammenspielt.
Schritt 18: Überschreiben Sie die toString
-Methode
Eine letzte Sache, und auch dies ist optional. Aber es ist auch als Debug-Tool sehr nützlich, so dass es sich normalerweise innerhalb weniger Anwendungen bezahlt macht.
Falls Sie es noch nicht erfahren haben, die toString
-Methode existiert auf allen Object (sie ist in Object
deklariert und definiert, der Überklasse, von der alle anderen Klassen erben, ob Sie es wollen oder nicht). Es kann explizit aufgerufen werden, aber das Praktische ist, dass es in einigen Fällen automatisch aufgerufen wird. Wenn Sie beispielsweise object an die Trace
-Funktion übergeben, muss für jedes Objekt, das noch kein String
ist, toString
aufgerufen werden, um sicherzustellen, dass es für das Ausgabebedienfeld gut formatiert ist. Es wird sogar aufgerufen, wenn mit Objekten
zusammen mit Strings
gearbeitet wird, wie bei der Verkettung. Wenn Sie zum Beispiel dies schreiben:
"The answer to life, the universe, and everything is " + 42;
ActionScript ist intelligent genug, um 42
in eine String
-Darstellung der Number
umzuwandeln, bevor der String
verkettet wird. Der Versuch, einen String
und eine Number
hinzuzufügen, ist eine schlechte Nachricht, aber das Konvertieren einer Number
in einen String
und das anschließende Verketten mit einem anderen String
ist in Ordnung.
Wenn Sie also Ihre eigenen Klassen schreiben, können Sie eine toString
-Methode bereitstellen, die keine Argumente akzeptiert und einen String
zurückgibt, und einen beliebigen String
zurückgeben.
Im Fall von Events
-Ebjekten bietet Adobe hilfreicherweise eine formatToString
-Methode, damit alle Event
bei der Verfolgung ähnlich aussehen. Wir verwenden es in der Methode, die wir unserer Klasse hinzufügen werden:
override public function toString():String { return formatToString("SliderValue", "type", "sliderValue"); }
Notieren Sie sich zunächst die Methodensignatur. Auch hier handelt es sich um eine override
, sodass wir dieses Schlüsselwort haben. Es ist public
, nimmt keine Parameter an und gibt einen String
zurück (was offensichtlich sein sollte).
Beachten Sie als Nächstes die einzelne Zeile im Methodenrumpf. Wir rufen formatToString
auf, das in Event
definiert ist, damit es einfach zu verwenden ist. Das erste Argument, das wir ihm übergeben, ist der String
-Name der Klasse. Danach sind die Argumente offen. Sie können eine, 15 oder keine abgeben. Wir gehen in zwei durch. Egal wie viele Sie übergeben, sie sollten alle Strings
sein und mit den Eigenschaftsnamen Ihrer Klasse übereinstimmen. "type"
wird von Event
definiert, aber "sliderValue"
wird von unserer eigenen Klasse definiert. In jedem Fall wird der Name der Eigenschaft ausgegeben, gefolgt von einem Gleichheitszeichen, gefolgt vom tatsächlichen Wert dieser Eigenschaft. Kurz gesagt, es wird am Ende so aussehen:
[language="text"] [SliderValue type="sliderChange" sliderValue=0.34146341463414637]
Dies ist völlig funktionslos, aber sehr nützlich. Es kann einen schnellen Einblick in das Ereignis geben, wenn die Dinge nicht so funktionieren, wie Sie es sich vorstellen.
Schritt 19: Erstellen des Sliders
An dieser Stelle haben wir das Schlüsselkonzept dieses Tutorials durchgearbeitet: das Schreiben einer benutzerdefinierten Event
-Klasse. Aber wir müssen es wirklich auf die Probe stellen. Wir werden den Rest unserer Zeit damit verbringen, die einfache Slider-Anwendung zu erstellen, die zu Beginn des Tutorials in der Vorschau angezeigt wurde.
Wir haben bereits eine Projektordnerstruktur; Wir brauchen nur noch ein paar Dateien. Wir beginnen mit der FLA-Datei.
Erstellen Sie eine neue Flash-Datei (natürlich ActionScript 3.0) und speichern Sie sie als ActiveSlider.fla im Stammverzeichnis Ihres Projektordners. Ich gehe davon aus, dass Sie keine Schritt-für-Schritt-Anleitungen benötigen, um diese einfache FLA zusammenzustellen, sondern ich werde die Schlüsselelemente darstellen. Sie können auch die FLA-Datei im start-Ordner des Downloadpakets als Referenz verwenden oder diese FLA einfach in Ihren Projektordner kopieren und diesen Schritt als erledigt bezeichnen.
Es gibt drei Hauptobjekte auf der Bühne.
- Die Slider-Spur. Dies ist ein langer, schmaler Streifen, der anzeigt, wohin der Schieberegler verschoben werden kann. Der Slider bewegt sich "in" der Spur.
- Muss ein Filmclip sein
- Für die einfachste Mathematik sollte die Grafik so angeordnet sein, dass sich der Registrierungspunkt in der oberen linken Ecke befindet
- Nennen Sie es
track_mc
- In die obere Mitte legen; es sollte den größten Teil der Bühnenbreite einnehmen und Platz darunter haben.
- Der Rutschengriff. Dies ist ein schaltflächengroßes Element, das die aktuelle Position des Schiebereglers anzeigt. Es ist das Stück, das sich entlang der Strecke bewegt und auf die Maus reagiert.
- Muss ein Filmclip sein.
- Auch für Mathe sollte der Registrierungspunkt oben links sein
- Nennen Sie es
grip_mc
- Platzieren Sie es über der Schiene, so dass es vertikal mit der Schiene zentriert ist und irgendwo am linken und rechten Ende der Schiene liegt
- Es sollte oben auf der Schiene gestapelt werden, damit der Griff die Schiene verdeckt (auf eine höhere Schicht legen)
- Das Ausgabefeld. Dies ist ein Textfeld, das zu unseren eigenen Demonstrationszwecken den aktuellen Wert des Schiebereglers anzeigt.
- Muss ein dynamisches Textfeld sein.
- Nennen Sie es
output_tf
- Schriftarten sind belanglos; Stellen Sie es nach Belieben ein und betten Sie es nach Bedarf ein
- Platzieren Sie es im unteren Bereich der Bühne, damit es nicht mit dem Platzbedarf des Schiebereglers kollidiert.




Abgesehen vom Anschließen der Dokumentenklasse, die wir in zwei Schritten schreiben werden, ist die FLA einsatzbereit.
Schritt 20: Die ActiveSlider
-Klasse
Die wichtigste UI-Klasse, mit der wir arbeiten werden, ist die ActiveSlider
-Klasse. Dadurch wird EventDispatcher
erweitert, die beiden Movieclips auf der Bühne als Ziel festgelegt und die Mausinteraktivität für das Schiebereglerverhalten eingerichtet. Am aufregendsten ist, dass es ein SliderEvent
auslöst.
Erstellen Sie zunächst eine neue Klassendatei namens ActiveSlider.as im Ordner com/activetuts/slider Ihres Projekts. Diese Klasse ist nicht zu intensiv (zumindest nicht für unsere Zwecke hier. Eine Slider-Klasse könnte viel mehr in Anspruch nehmen), und ich werde den Code einfach vollständig präsentieren und im Laufe der Zeit diskutieren:
package com.activetuts.slider { import flash.display.*; import flash.events.*; import flash.geom.*;
Nichts Aufregendes, nur das Paket einrichten und importieren.
public class ActiveSlider extends EventDispatcher { private var _track:Sprite; private var _grip:Sprite; private var _grabOffset:Point;
Wir brauchen diese drei Eigenschaften. Die ersten beiden verfolgen die Sprite
(oder MovieClip
), aus denen der Schieberegler besteht. Der dritte wird beim Ziehen des Schiebereglergriffs verwendet; es hilft, die Position des Griffs von der Maus um einen Betrag relativ zu der Stelle zu halten, an der der Griff zuerst geklickt wurde.
public function ActiveSlider(track:Sprite, grip:Sprite) { _track = track; _grip = grip; if (_grip.parent != _track.parent) { throw new Error("The track and the grip Sprites are not in the same container.") } _grip.addEventListener(MouseEvent.MOUSE_DOWN, onDown); if (_grip.stage) { addStageListener(); } else { _grip.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); } }
Dies ist der Konstruktor. Es akzeptiert zwei Sprite
-Argumente, die zur Speicherung an die ersten beiden dieser Eigenschaften weitergegeben werden. Es führt dann eine einfache Überprüfung durch, um sicherzustellen, dass sich die beiden Sprite
im selben Koordinatenraum befinden, indem überprüft wird, dass ihre parent
Eigenschaften auf dasselbe Objekt verweisen. Wenn dies nicht der Fall ist, ist unsere Berechnung für die Platzierung des Griffs möglicherweise unzuverlässig, sodass wir einen Fehler ausgeben, um den Entwickler zu warnen. Der Rest des Konstruktors dient dem Hinzufügen von zwei Ereignis-Listenern. Das erste ist ein MOUSE_DOWN
-Ereignis und geradeaus. Die zweite versucht jedoch, der stage
ein MOUSE_UP
-Ereignis hinzuzufügen, das möglicherweise vorhanden ist oder nicht, je nachdem, ob sich das grid
-Sprite
in der Anzeigeliste befindet oder nicht. Die nächsten beiden Methoden könnten dies etwas klarer machen:
private function onAddedToStage(e:Event):void { _grip.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); addStageListener(); } private function addStageListener():void { _grip.stage.addEventListener(MouseEvent.MOUSE_UP, onUp); }
Die Methode onAddedToStage
ist ein Ereignis-Listener für das Ereignis ADDED_TO_STAGE
, das im Konstruktor eingerichtet wurde, jedoch nur, wenn das Sprite
-Sprite nicht bereits einen Verweis auf die stage
hatte. Die Methode addStageListener
fügt der stage
einfach den Ereignis-Listener MOUSE_UP
hinzu. Wenn also im Konstruktor eine stage
-Referenz vorhanden ist, rufen wir addStageListener
direkt auf. Wenn keine stage
-Referenz vorhanden ist, richten wir das Ereignis ADDED_TO_STAGE
ein, und wenn der Griff zur Anzeigeliste hinzugefügt wird und somit eine stage
-Referenz hat, wird die Methode onAddedToStage
ausgelöst, die dann wiederum addStageListener
aufruft. Es entfernt auch den Ereignis-Listener ADDED_TO_STAGE
, da wir dies nur einmal tun müssen.
private function onDown(e:MouseEvent):void { _grabOffset = new Point(e.localX, e.localY); _grip.addEventListener(Event.ENTER_FRAME, onFrame); } private function onUp(e:MouseEvent):void { _grip.removeEventListener(Event.ENTER_FRAME, onFrame); }
Als nächstes haben wir unsere beiden Maus-Ereignis-Listener. In onDown
besteht die Schlüsselzeile darin, dann einen ENTER_FRAME
-Ereignis-Listener hinzuzufügen. In onUp
entfernen wir diesen Listener. Auch in onDown
notieren wir, wo auf dem Griff der Mausklick tatsächlich stattgefunden hat, und speichern dies in _grabOffset
. Dies wird als nächstes in unsere onFrame
-Methode einfließen.
private function onFrame(e:Event):void { _grip.x = _grip.parent.mouseX - _grabOffset.x; var gripBounds = _grip.getBounds(_grip.parent); var trackBounds = _track.getBounds(_grip.parent); if (gripBounds.x < trackBounds.x) { _grip.x = _track.x; } else if (gripBounds.right > trackBounds.right) { _grip.x = trackBounds.right - gripBounds.width } trace(this.value); }
Dies ist der Kern unserer Slider-Logik. Diese Methode wird bei einem ENTER_FRAME
-Ereignis wiederholt ausgelöst, jedoch nur, wenn die Maus auf den Griff gedrückt wurde, und nur so lange, wie die Maus gedrückt bleibt.
Zuerst stellen wir die x
-Eigenschaft des Griffs so ein, dass sie mit der Mausposition übereinstimmt, wir müssen ihn nur basierend auf der ursprünglichen Mausposition versetzen, damit er sich reibungslos bewegt und nicht springt, sodass sich seine linke Kante an der Maus befindet.
Die nächsten beiden Zeilen berechnen die umgrenzenden Rechtecke der Griff- und Spur-Sprite
. Wir werden diese Rechtecke in der kommenden Mathematik verwenden, also halten wir die Dinge aufgeräumter, indem wir die Rechtecke im Voraus berechnen und in Variablen speichern.
Dann gibt es den if
-Block. Dies beschränkt unseren Schieberegler nur auf die Spur. Es ist eine einfache Überprüfung, ob das x
des Griffs, wie in der ersten Zeile der Methode berechnet, niedriger ist als das x
der Spur (links davon). Wenn dies der Fall ist, wäre es zu weit, daher müssen wir den Griff auf diesen Mindestwert verschieben. In ähnlicher Weise prüfen wir, ob die rechte Kante des Griffs größer ist als (rechts davon) die rechte Kante der Spur, und wenn ja, müssen wir sie auf diesen maximalen Wert zurückspulen.
Endlich haben wir eine zuverlässige Griffposition, und vorerst verfolgen wir nur den aktuellen Schiebereglerwert, der im letzten Code für die Klasse berechnet wird:
private function get value():Number { return (_grip.x - _track.x) / (_track.width - _grip.width); } } }
Dies ist ein einfacher Getter, obwohl die für den Rückgabewert verwendete Mathematik etwas verwirrend sein kann. Er bestimmt die aktuelle Griffposition als Prozentsatz des Bewegungsbereichs des Griffs. Es wäre offensichtlicher, wenn es nur so wäre:
return _grip.x / _track.width;
...was vernünftig ist, aber nicht berücksichtigt, dass der Grip nicht wirklich die gesamte Breite der Strecke abdeckt. Es geht bis zum linken Rand, aber nur bis zum rechten Rand der Spur abzüglich der Breite des Griffs. Das ist also genauer:
return _grip.x / (_track.width - _grip.width);
Dies macht die Breite, um die wir den Bewegungsumfang teilen. Es kann jedoch immer noch ein Gotcha sein, dass die Spur von ihrem Container nach links oder rechts versetzt werden kann, was bedeutet, dass die Werte, die wir erhalten, nicht ganz richtig sind. Wir müssen das neutralisieren, indem wir die x
-Position der Spur vom x
des Grips subtrahieren, und wir enden mit Folgendem:
return (_grip.x - _track.x) / (_track.width - _grip.width);
Als Referenz ist hier die komplette Klasse, wobei meine Wanderungen weggelassen wurden:
package com.activetuts.slider { import flash.display.*; import flash.events.*; import flash.geom.*; public class ActiveSlider extends EventDispatcher { private var _track:Sprite; private var _grip:Sprite; private var _grabOffset:Point; public function ActiveSlider(track:Sprite, grip:Sprite) { _track = track; _grip = grip; if (_grip.parent != _track.parent) { throw new Error("The track and the grip Sprites are not in the same container.") } _grip.addEventListener(MouseEvent.MOUSE_DOWN, onDown); if (_grip.stage) { addStageListener(); } else { _grip.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); } } private function onAddedToStage(e:Event):void { _grip.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); addStageListener(); } private function addStageListener():void { _grip.stage.addEventListener(MouseEvent.MOUSE_UP, onUp); } private function onDown(e:MouseEvent):void { _grabOffset = new Point(e.localX, e.localY); _grip.addEventListener(Event.ENTER_FRAME, onFrame); } private function onUp(e:MouseEvent):void { _grip.removeEventListener(Event.ENTER_FRAME, onFrame); } private function onFrame(e:Event):void { _grip.x = _grip.parent.mouseX - _grabOffset.x; var gripBounds = _grip.getBounds(_grip.parent); var trackBounds = _track.getBounds(_grip.parent); if (gripBounds.x < trackBounds.x) { _grip.x = _track.x; } else if (gripBounds.right > trackBounds.right) { _grip.x = trackBounds.right - _grip.width } trace(this.value); } private function get value():Number { return (_grip.x - _track.x) / ((_track.width - _grip.width) - _track.x); } } }
Wir haben unsere SliderEvent
-Klasse noch nicht hinzugefügt. Wir werden einen separaten Schritt unternehmen, um das zu tun. Aber zuerst benötigen wir unsere Dokumentklasse, damit wir den ActiveSlider
tatsächlich verwenden können.
Schritt 21: Die Document-Klasse
Wir benötigen eine weitere Datei, damit es funktioniert: unsere Dokumentklasse. Erstellen Sie eine neue Klassendatei mit dem Namen SliderDemo
im Projektstammordner. Fügen Sie den folgenden Code hinzu:
package { import flash.display.*; import flash.events.*; import com.activetuts.slider.ActiveSlider; public class SliderDemo extends Sprite { private var _slider:ActiveSlider; public function SliderDemo() { _slider = new ActiveSlider(track_mc, grip_mc); } } }
Dies ist viel einfacher als unsere ActiveSlider
-Klasse. Es richtet wirklich nur einen ActiveSlider
in die Eigenschaft namens _slider
ein.
Gehen Sie zurück zur FLA-Datei und geben Sie SliderDemo in das Dokumentklassenfeld ein, und Sie sollten dies ausprobieren können. Der Schieberegler sollte in der Lage sein, sich hin und her zu bewegen und sich auf die Breite der Spur zu beschränken.
Nun zu einer letzten Aufgabe. Wir müssen ein SliderEvent.CHANGE
-Ereignis aussenden und darauf warten. Wir werden das als nächstes tun.
Schritt 22: Dispatching des SliderEvent
Kehren Sie zur ActiveSlider-Klasse zurück, und nehmen Sie eine einzeilige Änderung an der onFrame
-Methode vor:
private function onFrame(e:Event):void { _grip.x = _grip.parent.mouseX - _grabOffset.x; var gripBounds = _grip.getBounds(_grip.parent); var trackBounds = _track.getBounds(_grip.parent); if (gripBounds.x < trackBounds.x) { _grip.x = _track.x; } else if (gripBounds.right > trackBounds.right) { _grip.x = trackBounds.right - _grip.width } dispatchEvent(new SliderEvent(SliderEvent.CHANGE, this.value)); }
Wir haben die Ablaufverfolgung entfernt und durch eine echte Live-Ereignissendung ersetzt. Damit dies funktioniert, müssen wir jedoch die SliderEvent
-Klasse importieren:
package com.activetuts.slider { import flash.display.*; import flash.events.*; import flash.geom.*; import com.activetuts.events.SliderEvent;
Schritt 23: Warten auf das SliderEvent
Kehren Sie schließlich zur SliderDemo-Klasse zurück, und ändern Sie sie so, dass sie auf das SliderEvent
wartet und darauf reagiert:
package { import flash.display.*; import flash.events.*; import com.activetuts.slider.ActiveSlider; import com.activetuts.events.SliderEvent; public class SliderDemo extends Sprite { private var _slider:ActiveSlider; public function SliderDemo() { _slider = new ActiveSlider(track_mc, grip_mc); _slider.addEventListener(SliderEvent.CHANGE, onSliderChange); } private function onSliderChange(e:SliderEvent):void { trace(e); output_tf.text = e.sliderValue.toString(); } } }
Wir importieren erneut die SliderEvent
-Klasse, und nachdem wir den ActiveSlider
erstellt haben, fügen wir dem Schieberegler einen Listener namens onSliderChange
hinzu. Diese Methode ist die größte Ergänzung, aber immer noch ein regelmäßiger Ereignis-Listener. Es ist ähnlich wie bei jedem anderen Ereignislistener, nur stellen wir sicher, dass wir das Ereignisargument als SliderEvent
eingeben, denn das ist es, was wir bekommen.
Die erste Codezeile ist etwas überflüssig, aber ich wollte sehen, was passiert, wenn Sie unser SliderEvent
-Objekt verfolgen. Wenn Sie dies ausführen, sehen Sie eine für Flash typische Formatierung des Ereignisobjekts.



Die zweite Zeile macht das, wonach wir anfangs gesucht haben. Es greift einfach die sliderValue
-Eigenschaft ab, wandelt sie in einen String
um und klebt diesen String
dann in das TextField
auf der Bühne, damit wir den Schiebereglerwert im Film sehen können.
Step 24: Wrapping Up
Wenn Sie mit dem Rollout Ihrer eigenen benutzerdefinierten Ereignisse beginnen, beginnen Sie mit ActionScript 3 so zu arbeiten, wie es verwendet werden sollte. Ereignisse helfen Ihnen, Klassen voneinander zu entkoppeln, und ein gut strukturierter Ereignisfluss in Ihrer Anwendung kann wirklich den Unterschied zwischen etwas, mit dem man einfach arbeiten kann, und etwas, das fehlerhaft und temperamentvoll ist, ausmachen. Mit diesem (theoretisch) letzten Teil von AS3 101 solltest du auf dem richtigen Weg sein, ein Ninja zu werden.
Danke fürs Lesen, und ich sehe dich wieder hier auf Activetuts+, bevor du es weißt!