Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. ActionScript

AS3 101: Eventos - Basix

Read Time: 35 mins
This post is part of a series called AS3 101.
AS3 101: OOP - Introducing Design Patterns
AS3 101: Quick Tip - Dispatching Events Without Extending EventDispatcher

Spanish (Español) translation by Xiomara Reynoso (you can also view the original English article)

Para este capítulo de AS3 101, nos sumergiremos en la mecánica del sistema de eventos Flash. Si has estado siguiendo hasta ahora, habrás visto eventos en uso, que se remontan al primer episodio de la serie. El editor y yo sentimos que era hora de escribir algo para incluirlo formalmente en el plan de estudios, así que si alguna vez has visto esas líneas de código sobre agregar oyentes de eventos o enviar eventos, y no te has dado cuenta, entonces este es el tutorial para ti.

Ya existe un tutorial de Activetuts+ sobre los conceptos básicos de los eventos, por lo que el enfoque de este tutorial será el envío de eventos de tus propias clases, incluida la creación de tipos de eventos y objetos personalizados.

Para tener éxito con este tutorial, debes sentirse cómodo escribiendo y utilizando tus propias clases en ActionScript 3, así como sintiéndote seguro con el uso de los eventos existentes proporcionados por Flash, como MouseEvent.CLICK o Event.ENTER_FRAME. Nos centraremos principalmente en el envío de eventos personalizados de clases personalizadas.


Vista previa

Dedicaremos mucho tiempo a la teoría para este tutorial, pero al final construiremos un control deslizante simple que despacha sus propios eventos:


Paso 1: ¿Por qué usar el despacho de eventos?

Este ejemplo es en realidad un ejemplo bastante simple de por qué querrías enviar tus propios eventos. Cuando escribes tus propias clases, lo ideal es mantenerlas en sus propias cajas negras y encapsuladas. Pero aún necesitas que los diversos objetos inter operen para crear un programa útil.

El modelo de eventos proporcionado por ActionScript 3 es una forma bastante buena y cómoda de facilitar la comunicación entre las clases, manteniendo al mismo tiempo una separación de responsabilidades en las clases. Por lo tanto, si escribimos nuestra propia clase personalizada, como las muestras de clase ActiveSlider anteriores, tenemos la necesidad de permitir que otros objetos sean conscientes de cuándo el control deslizante cambia su valor. Si el control deslizante puede enviar su propio evento de cambio, entonces otros objetos que necesitan saber esa información pueden suscribirse fácilmente y ser notificados.

Personalmente, encuentro la necesidad de enviar mis propios eventos en mis clases tan común que mi plantilla de clase configura cada nueva clase con la repetición que necesita para poder hacerlo. A medida que aprendas a mantener los objetos discretos, recurrirás al envío de eventos como la técnica más común para hacerlo.


Paso 2: Cómo enviar tus propios eventos

Tengo buenas noticias: enviar tus propios eventos es en realidad muy simple. Es uno de los principios básicos de ActionScript 3, integrado en Flash Player, y como tal, solo hay una cosa que debes hacer para obtener la capacidad de enviar eventos. Esta única cosa es:

Extender EventDispatcher

Eso es todo: al escribir tu clase, usa la línea:

Por supuesto, debes importar EventDispatcher, que se encuentra en el paquete flash.events. Lo más probable es que necesites otras clases en el paquete, por lo que podría ser más conveniente simplemente importar el paquete con un comodín.


Paso 3: Despacho

Ahora estás configurado para enviar un evento. Todo lo que necesitas hacer ahora es llamar a un método proporcionado por EventDispatcher llamado dispatchEvent. Fácil de entender, ¿no?

Al llamar a dispatchEvent, debes proporcionar al menos un argumento, un objeto Event. Todos los objetos Event integrados están en el paquete flash.events, así que aquí es donde esa importación de comodines es útil. Cada tipo de objeto Event tendrá sus propios requisitos, pero la mayoría de las veces simplemente necesitas pasarle un solo argumento, también. Este argumento es el tipo de evento, que es una cadena que nombra el evento, como "click" o "complete". Estos se escriben más comúnmente como MouseEvent.CLICK o Event.COMPLETE, pero el resultado final es el mismo; es un identificador que separa un tipo de evento de otro y permite que un objeto Event administre varios tipos de eventos.

Entonces, poniéndolo todo junto, si quisieras enviar un evento "complete", podrías hacerlo así:

Simplemente suelta esa línea (o una similar) en cualquier método que sea apropiado en tu clase. Tu clase utilizará su sistema de envío de eventos heredado y cualquier oyente será notificado por ti. Hablando de oyentes, echemos un breve vistazo a ellos también.


Paso 4: Escucha

Cualquier otro objeto de la aplicación puede escuchar los eventos personalizados ahora. Mejores noticias: esto no es diferente a registrarse para eventos para las clases incorporadas. En el paso anterior, configuramos nuestra clase hipotética para enviar un evento COMPLETE. Para escuchar ese evento, podríamos escribir esta línea en otro lugar de nuestro programa:

Y eso es todo. Esto debería parecer familiar para cualquiera que haya conectado un oyente COMPLETE a un Loader, por ejemplo, así que no me detendré más en esto.


Paso 5: Dónde enviar

El lugar donde realmente colocas la línea de código dispatchEvent requiere cierta consideración. Normalmente, debe ser la última línea de código del método en el que está escrito. Esto es para que cualquier otro código que también se ejecute en ese método pueda establecer propiedades o actualizar de otro modo el estado interno del objeto. Al distribuir después de que se complete esta actualización interna, el objeto se encuentra en un estado "limpio" en el momento del envío.

Consideremos, por ejemplo, nuestro ejemplo de trabajo. Digamos que el evento COMPLETE se trata del procesamiento de algunos datos; un montón de datos tan grande que tardará varios segundos en procesarse por completo, por lo que el propósito del objeto es manejar el procesamiento de forma asincrónica para no bloquear la interfaz de usuario. Y estamos enviando el evento COMPLETE como una forma de decir que los datos han sido procesados.

Ahora supongamos que el método principal en cuestión se parece a esto:

De acuerdo, no es muy realista, pero ilustra el punto. Seguimos construyendo los datos internos hasta que alguna otra lógica interna determina que hemos terminado, momento en el que luego escribimos algunos bits finales de datos para cerrar la operación.

Ahora, agreguemos la llamada dispatchEvent:

¿Cuál es el problema con este enfoque? Cualquier código que se ejecute dentro de los agentes de escucha para el evento COMPLETE se ejecutará antes de que se llame al método closeData. Por lo tanto, el estado del despachador cambia más de una vez dentro del intervalo del método processDataChunk y no es "estable" hasta después de la llamada closeData. Sin embargo, les decimos a todos nuestros oyentes que estamos completos antes de esa llamada. Esto podría conducir a algunos errores difíciles de rastrear donde un objeto afirma estar COMPLETE, pero realmente no lo es. La solución obvia es cambiar algunas líneas:


Paso 6: Eventos personalizados

Todos están listos para enviar sus propios eventos. Ahora, ¿qué debes enviar? Hay algunas opciones a considerar:

  1. Simplemente reutiliza un objeto de evento y un tipo de evento ya proporcionados por Flash Player
  2. Reutilizar un objeto de evento existente, pero proporcionar un tipo de evento personalizado
  3. Volver a enviar un evento existente
  4. Crea un objeto de evento personalizado
  5. Empujar vs. tirar

Esta primera opción ya la hemos visto en nuestros ejemplos anteriores. Tenemos la necesidad de enviar un evento relacionado con la finalización de algún proceso, y como sucede, Flash proporciona un tipo de evento (COMPLETE) asociado con un objeto de evento (Event) que se ajusta a nuestros criterios. No tenemos necesidad de proporcionar datos adicionales con el evento. Enviar un evento Event.COMPLETE es todo lo que necesitamos.

Exploraremos estas otras opciones en los próximos pasos.


Paso 7: Tipos de eventos personalizados

Como se insinúa en el paso "Enviar", los tipos de eventos son simplemente identificadores de String. Técnicamente pueden ser cualquier String que quieras. Por lo general, es suficiente convertirlo en una sola palabra (como "completo" o "clic") o una frase muy corta (como "ioError" o "keyFocusChange"); solo tienes que ser único dentro del ámbito de eventos disponibles de un despachador de eventos determinado.

Además, a los objetos Event (incluidas las subclases, como MouseEvent o ProgressEvent) realmente no les importa qué tipo de evento se les da cuando se crea una instancia. Un EventDispatcher con gusto enviará eventos de cualquier tipo de identificador y de cualquier clase (siempre que sea la clase Event o una subclase).

El resultado de esto es que puedes crear tu propio tipo de evento String, enviarlo y configurar oyentes con él, y todo estará bien. Esto es útil cuando deseas distribuir un evento, pero no necesariamente puedes encontrar una buena representación de la naturaleza del evento en las clases integradas.

Por ejemplo, es posible que tengas una clase que actúe como coordinador para varias cosas a la vez: cargar algún XML, cargar algunas imágenes basadas en los datos XML y crear un diseño basado en los tamaños de las imágenes cargadas, listo para una animación inicial, momento en el que deseas distribuir un evento. Si bien el evento COMPLETE puede ser adecuado, puedes sentir que un evento "listo" encapsula el significado de manera más apropiada.

Esto es tan simple como decidir sobre la String a usar y luego usarla. Úsalo tanto al agregar oyentes como al enviar el evento. Si la String coincide, el evento llegará a donde debe ir. Por ejemplo, esta es una lista parcial de una clase hipotética:

Y código de otra parte en el mismo programa:

Y eso funcionará

Sin embargo, vale la pena mencionar mientras estamos aquí que escribir String coincidentes en todo el lugar no es una buena práctica. La posibilidad de error es alta, y el sistema de eventos no le dirá que ha escrito "raedy" en lugar de "ready". El hecho de que el sistema de eventos sea flexible y fácil de usar, simplemente páselo cualquier string antigua para el tipo de evento, también es una debilidad. Tu despachador aceptará con gusto a un oyente para cualquier cosa, incluso un evento "raedy". Realmente no reconcilia qué tipos de eventos están registrados con qué tipos de eventos se envían realmente.

Para ayudar a evitar esto, el enfoque estándar es simplemente poner la string que deseas usar en una constante estática en algún lugar, y luego nunca volver a usar esa string literal. Solo usa la constante. Por supuesto, la posibilidad de errores tipográficos es simplemente excelente como antes, pero si estás utilizando una constante READY y no la sting literal "ready", un error de tipo desencadenará una advertencia del compilador. Podrás corregir tu error de forma rápida y sencilla. Un error de tipo con el literal Strings no produce ningún error del compilador, ni produce un error en tiempo de ejecución. Lo único que sucede es que el SWF no parece funcionar correctamente, porque el oyente de eventos no se dispara.

Con esto en mente, es más común almacenar estas constantes en la clase Event relacionada. Llegaremos a clases de event personalizadas en solo unos pocos pasos. Pero en la situación descrita en este paso (es decir, estamos reutilizando una clase Event, pero no un tipo de evento), me parece más conveniente simplemente almacenar esa constante en la clase dispatcher. Así que podríamos optar por hacer esto:

Y:

Esto nos da la seguridad de almacenar tipos de eventos en constantes, sin forzar el inconveniente de crear una clase Event completa que no necesitamos. Debo enfatizar que esta es una elección estilística, y puedes sentirse libre de usar esta técnica o no. Sentí que merecías una explicación, para que pudieras tomar tu propia decisión informada. En cualquier sentido, definitivamente debes almacenar tu tipo de evento personalizado Strings en constantes estáticas. Dónde se definen esas constantes estáticas depende de ti.


Paso 8: Reenspachar eventos

Hay varias veces en que una clase (llamémosla ClassX) posee una propiedad que se escribe como otra clase (la llamaremos ClassY), mientras que ella misma es propiedad de una tercera clase (¿qué tal ClassZ?). ClassX está escuchando un evento de ClassY, pero no solo queremos que ClassX responda al evento, sino que también queremos considerar que ClassX debe enviar un evento similar (o incluso el mismo) para que ClassZ también pueda tomar medidas adicionales.

Como ejemplo más concreto, tenemos una clase (esta será "ClassX") que es una especie de administrador de datos. Carga un documento XML, lo analiza y almacena datos del XML en sus propias propiedades. Por lo tanto, tiene un objeto URLLoader (esto sería "ClassY"), y escucha el evento Event.COMPLETE para cuando se carga el documento XML.

Luego tenemos una clase de documento principal que posee el administrador de datos (la clase de documento es "ClassZ"). Está coordinando la carga de datos con otros elementos de la interfaz de usuario, por lo que quiere saber cuándo se cargan y están listos los datos, para poder proceder a crear y diseñar elementos de la interfaz de usuario en función de los datos.

Podríamos hacer esto:

Pero también podríamos hacer esto:

Aquí simplemente reenviamos el evento existente. No solo reutilizamos el tipo de evento y la clase Event, sino que en realidad estamos reutilizando todo el objeto Event a medida que se pasa a nuestro propio oyente.

No es ciencia espacial, pero es una pequeña técnica útil que sorprendentemente no es tan obvia.

"Pero espera", debes estar pensando, "si redisparáramos un evento que se originó a partir del objeto URLLoader, ¿no sería el target del evento aún _xmlLoader cuando vuelva a la clase de documento?" Y tendrías un punto muy bueno y reflexivo, y estaría orgulloso de ti por pensar tan cuidadosamente, pero estarías equivocado.

Una cosa bastante mágica sucede cuando se reeparche los eventos. La propiedad de target se establece en el despachador actual. Puedes encontrar un ejemplo práctico del código en este paso en el paquete de descarga, titulado reenspache.

En realidad, no es tan mágico. Al llamar a dispatchEvent, si el objeto Event que se pasa ya tiene un target establecido, se llama al método clone en el Event, creando una copia idéntica pero discreta del Event original, excepto por el valor contenido en el target.


Paso 9: Objetos de evento personalizados

Todo lo mencionado hasta ahora es algo que querrás saber. Pero llegará un momento en que lo mejor que puedes hacer es enviar tu propio evento personalizado. No solo un tipo de evento personalizado, sino toda una clase de event personalizada.

El proceso para hacer esto es sencillo, solo necesitas seguir algunos pasos. Discutiremos esto a su debido tiempo. Ten en cuenta que bastante de esto es código repetitivo, y podrías crear fácilmente una plantilla para una subclase event y cambiar solo algunas piezas clave y estar apagado y en ejecución. Los pasos generales, en forma abreviada como si supieras de qué estaba hablando:

  1. Subclass Event
  2. Llama a super(...)
  3. Almacenar tipos de eventos en constantes estáticas públicas
  4. Declara propiedades privadas para contener datos personalizados
  5. Crear obtenedores públicos para proporcionar acceso de solo lectura a la información personalizada
  6. (Opcional) Invalidar el método de clone
  7. (Opcional) Invalidar el método toString

Para explicar estos procesos más profundamente, comenzaremos nuestro proyecto de control deslizante y crearemos el SliderEvent que necesitaremos para eso. Por lo tanto, debemos comenzar nuestro proyecto antes de que podamos escribir algo de código, por lo que una desviación rápida en el siguiente paso, luego comenzaremos a escribir una clase de event personalizada.


Paso 10: Crear la estructura del proyecto

Mantendremos las cosas bastante simples para este, sin embargo crearemos paquetes para nuestras clases.

Comienza creando una carpeta para todo el proyecto. El mío se llamará slider.

Dentro de esto, crea una carpeta com, y dentro de eso, una carpeta activetuts.

Ahora crea dos carpetas dentro de activetuts: eventos y ui. La estructura de carpetas final debería tener un aspecto similar al siguiente:

  • slider
    • com
      • activetuts
        • events
        • slider

Ahora volvamos a nuestra clase de Event.


Paso 11: Event de subclase

Primero, crea un nuevo archivo de texto en la carpeta slider/com/activetuts/events y llámalo SliderEvent.as. Iremos en el repetitivo para cualquier clase:

No debería haber nada sorprendente aquí, y si tienes plantillas de ActionScript para tu editor de texto, ni siquiera deberías tener que escribir tanto.

Ahora, modificaremos esto para que extienda el event.

Como puedes ver, simplemente importamos la clase Event, agregamos extend Event a la definición de clase.


Paso 12: Llama al super

Nuestra superclase puede manejar mucho por nosotros, lo cual es genial, pero debemos asegurarnos de inicializar la superclase correctamente cuando inicializamos nuestra subclase. Necesitamos configurar el constructor con argumentos que coincidan con los que se encuentran en el constructor de Event, y pasarlos junto con una llamada a super.

Se trata, hasta ahora, de técnicas básicas de sub clasificación. De hecho, dependiendo de la destreza de tu editor con las plantillas, es posible que puedas especificar una superclase cuando crees el archivo y hacer todo esto por ti mismo. Flash Builder, por ejemplo, es capaz de hacer esto.


Paso 13: Almacenar tipos de eventos en constantes estáticas públicas

Presumiblemente, habrá uno o más tipos de eventos asociados con esta clase de evento. Al igual que el evento COMPLETE está asociado con la clase Event y el CLICK incluso con la clase MouseEvent, nuestra clase de evento personalizada probablemente tendrá tipos de eventos personalizados.

Esto es tan simple como escribir una línea como la siguiente para cada tipo de evento que desees agregar:

Hagámoslo ahora para la clase SliderEvent.

Teóricamente podríamos usar nuestra clase ahora. Podemos usar SliderEvent en dispatchEvent, y escuchar y crear eventos con el tipo de evento SliderEvent.CHANGE.

Pero no nos detendremos ahí. Hay más que considerar. Pero antes de hacer más escritura de código, necesitamos tomar otro desvío hacia la teoría.


Paso 14: Empujar vs. Tirar

Cuando se envía un evento, a veces es suficiente simplemente saber que el evento ha ocurrido. Por ejemplo, la mayoría de las veces que está interesado en Event.ENTER_FRAME eventos, Event.COMPLETE o TimeEvent.TIMER, probablemente solo desees saber que el evento ocurrió. Sin embargo, hay otros momentos en los que probablemente quieras saber más. Al escuchar MouseEvent.CLICK, es posible que le interese saber si la tecla shift se mantuvo presionada o las coordenadas del ratón en el momento del clic. Si estás escuchando ProgressEvent.PROGRESS, lo más probable es que desees saber el progreso real de la carga; es decir, cuántos bytes se han cargado y cuántos hay que cargar en total.

La diferencia entre estas dos metodologías a veces se conoce como "push" y "pull". Esos términos se refieren a cómo el agente de escucha de eventos obtiene datos relacionados con el evento. Si los datos se "empujan", entonces hay datos almacenados dentro del objeto de evento, y para obtener los datos, el oyente simplemente necesita usar propiedades en el objeto de evento. Sin embargo, si los datos se deben "extraer", generalmente el objeto de evento tiene muy poca información contenida en su interior, solo las necesidades: el tipo, el objetivo, etc. Este objetivo, sin embargo, es indispensable, ya que proporciona acceso al despachador de eventos al agente de escucha de eventos, lo que permite al oyente obtener los datos que necesita del despachador.

En otras palabras, puedes enviar un montón de datos al oyente dentro del objeto de evento, o puedes requerir que el oyente extraiga los datos del despachador según sea necesario.

Los pros y los contras de cada técnica son algo equilibrados, en mi opinión, y el camino que elija para tu objeto de evento depende de la situación en cuestión, y no un poco de la preferencia personal.

Anexo A:

Pros Contras
Empujar
  • Los datos son fácilmente accesibles en el objeto de evento
  • Es posible que estés presionando datos que no son innecesarios. Hinchar el objeto de evento con un montón de datos que rara vez se usan podría provocar problemas de memoria o rendimiento.
Tirar
  • Muy fácil de escribir. Probablemente no necesites una clase Event personalizada para ejecutar un evento de extracción.
  • Muy fácil de usar. Si es solo una clase Event, el único argumento requerido es el tipo de evento.
  • Si los datos que comúnmente se extraen del despachador son costosos de calcular y devolver, es posible que estés teniendo un impacto en el rendimiento al requerir que el despachador entregue continuamente esa información.
  • Algunos datos pueden ser difíciles de extraer, por ejemplo, KeyboardEvent tiene una propiedad keyCode para detallar la tecla que se presionó para desencadenar el evento.

Esta podría ser una buena discusión para los comentarios; Estoy seguro de que muchos de ustedes que leen tienen sentimientos apasionados sobre qué metodología es mejor. Personalmente, trato de encontrar el método que mejor se adapte a la situación.

Dicho esto, vale la pena señalar que hasta este punto nuestra clase SliderEvent es bastante "pull-ish". Por el bien de la ilustración, y porque no es una idea terrible (aunque se me ocurrieron varias de ellas), continuaremos haciendo de este un evento que empuje datos junto con él; es decir, el valor del control deslizante cuando se cambió.


Paso 15: Declarar propiedades privadas para mantener datos personalizados

Para implementar un evento push, necesitamos tener un lugar para almacenar los datos que se están empujando. Agregaremos una propiedad privada para ese propósito.

Aún deberías tener SliderEvent abierto (si no... ¿A qué estás esperando?). Agrega la línea resaltada:

A continuación, modificaremos el constructor para que podamos aceptar un parámetro de valor y estableceremos la propiedad privada con eso:

De esta manera podemos crear fácilmente el SliderEvent y configurar sus datos push en una línea.

¿Por qué usar propiedades privadas? En este caso, queremos proteger los datos. En mi opinión, los datos relacionados con un evento son inmutables, siempre y cuando estén asociados con el evento. Ser capaz de cambiar los datos de un objeto de evento es como editar un libro de texto de historia. Para ser justos, esta es mi opinión y el estándar utilizado por Adobe con sus clases incorporadas es usar propiedades grabables (técnicamente usan propiedades privadas y getters y setters públicos, pero el resultado final es el mismo).


Paso 16: Crea obtenedores públicos para los datos personalizados

Por lo tanto, el siguiente paso sería asegurarnos de que podemos acceder a los datos que se están empujando. Una propiedad privada por sí sola no es útil para este propósito. Por lo tanto, necesitamos escribir un getter público para el _sliderValue propiedad. Elegiremos no escribir un setter, para que la propiedad se convierta en de solo lectura (como se discutió en el último paso).

Agrega este método a la clase:

Esto agrega un getter para que podamos acceder al sliderValue de manera similar a una propiedad. Estoy eligiendo no agregar el setter coincidente. Puedes agregar uno si crees que vale la pena.


Paso 17: Invalidar el método de clone

Mencioné el método de clone hace un tiempo. Probablemente no llamarás mucho al clon tú mismo, pero no es una mala idea anular el método de clone para que tu evento personalizado se juegue bien con el sistema de eventos.

Agrega este método a tu clase:

Primero, observa la firma de este método. Estamos usando override porque este método se declara en Event y lo estamos heredando. También devuelve un objeto de tipo Event. Asegúrate, al escribir la anulación del clon, de que has puesto el tipo de retorno correcto. Es fácil olvidar y poner el tipo de tu clase allí, pero eso causará un error de anulación incompatible, porque los tipos de retorno deben coincidir.

Todo lo que realmente estamos haciendo en la carne del evento es crear un nuevo SliderEvent y pasar los mismos valores que hemos almacenado en el objeto de evento actual. Esto crea una copia idéntica pero discreta: un clon.

Este es un paso opcional, pero es una victoria rápida y garantiza que tu evento personalizado se juegue bien con el resto del sistema de eventos.


Paso 18: Invalidar el método toString

Una última cosa, y de nuevo esto es opcional. Pero también es muy útil como herramienta de depuración, por lo que generalmente se paga por sí misma en unos pocos usos.

En caso de que aún no se te ha dicho, el método toString existe en todos los objetos (se declara y define en Object, la clase über de la que heredan todas las demás clases, te guste o no). Se puede llamar explícitamente, pero lo útil es que se llama automáticamente en varios casos. Por ejemplo, cuando pase el objeto a la función de trace, cualquier objeto que no sea ya una string tendrás que toString para asegurarte de que tienes un formato agradable para el panel Salida. Incluso se llama cuando se trabaja con object junto con String, como con la concatenación. Por ejemplo, si escribes esto:

ActionScript es lo suficientemente inteligente como para convertir 42 en una representación String del Number antes de concatenar el String. Intenta agregar una string y un Number es una mala noticia, pero convertir un Number en una string y luego concatenarlo con otra string está bien.

Por lo tanto, cuando escribes tus propias clases, puedes proporcionar un método toString, que no toma argumentos y devuelve un String, y devuelve el String que desees.

En el caso de los objetos Event, Adobe proporciona de forma útil un método formatToString para ayudar a que todos los events se vean similares cuando se rastrean. Lo usaremos en el método que estamos a punto de agregar a nuestra clase:

Primero, anote la firma del método. Una vez más, es una override, por lo que tenemos esa palabra clave. Es public, no toma parámetros y devuelve un String (que debería ser obvio).

A continuación, anota la línea única en el cuerpo del método. Llamamos formatToString, que se define en Event, por lo que es fácil de usar. El primer argumento que le pasamos es el nombre String de la clase. Después de eso, los argumentos son abiertos. Puedes pasar en uno, 15 o ninguno. Estamos pasando en dos. No importa cuántos pases, todos deben ser Strings y deben coincidir con los nombres de las propiedades de tu clase. "type" está definido por Event, pero "sliderValue" está definido por nuestra propia clase. De cualquier manera, lo que sucede es que se imprime el nombre de la propiedad, seguido de un signo igual, que es seguido por el valor real de esa propiedad. En resumen, terminará viendo así:

Esto es completamente no funcional pero muy útil. Puede proporcionar una visión rápida del evento cuando las cosas no están funcionando de la manera que crees que deberían.


Paso 19: Construyendo el control deslizante

En este punto, hemos pasado por el concepto clave de este tutorial: escribir una clase de event personalizada. Pero realmente tenemos que ponerlo a prueba. Pasaremos el resto de nuestro tiempo creando la sencilla aplicación deslizante que se previsualizó al principio del tutorial.

Ya tenemos una estructura de carpetas de proyecto; solo necesitamos algunos archivos más. Comenzaremos con el archivo FLA.

Crea un nuevo archivo Flash (ActionScript 3.0, por supuesto) y guárdalo como ActiveSlider.fla en la raíz de la carpeta del proyecto. Voy a asumir que no necesitas detalles paso a paso sobre cómo armar este FLA simple, y en su lugar presentaré los elementos clave. También puedes usar el archivo FLA que se encuentra en la carpeta de inicio del paquete de descarga como referencia, o incluso simplemente copiar ese FLA a la carpeta de tu proyecto y llamar a este paso hecho.

Hay tres objetos principales en el escenario.

  1. La pista deslizante. Esta es una tira larga y estrecha que indica hacia dónde se puede mover el control deslizante. El control deslizante se mueve "en" la pista.
    • Debe ser un clip de película
    • Para facilitar las matemáticas, debes tener la obra de arte dispuesta de modo que el punto de registro esté en la esquina superior izquierda
    • Nómbralo track_mc
    • Colócalo en el centro superior; debe ocupar la mayor parte del ancho del escenario y tener espacio debajo de él.
  2. El agarre deslizante. Este es un elemento del tamaño de un botón que indica la posición actual del control deslizante. Es la pieza que se mueve a lo largo de la pista y responde al ratón.
    • Debe ser un clip de película.
    • Una vez más, para las matemáticas, debes tener el punto de registro en la parte superior izquierda
    • Nómbralo grip_mc
    • Colócalo sobre la pista, de modo que esté centrado verticalmente con la pista, y en algún lugar dentro de los extremos izquierdo y derecho de la pista.
    • Debe apilarse en la parte superior de la pista, de modo que el agarre oscurezca la pista (colócala en una capa más alta)
  3. El campo de salida. Este es un campo de texto que, para nuestros propios fines de demostración, muestra el valor actual del control deslizante.
    • Debe ser un campo de texto dinámico.
    • Nómbralo output_tf
    • Las fuentes son intrascendentes; Configúralo en lo que desees e incrusta según sea necesario
    • Colócalo en la parte inferior del escenario, para que no entre en conflicto con el espacio requerido por el control deslizante.
The stage of our FLAThe stage of our FLAThe stage of our FLA

Además de conectar la clase de documento, que escribiremos en dos pasos, el FLA está listo para los negocios.


Paso 20: La clase ActiveSlider

La clase de interfaz de usuario principal con la que trabajaremos es la clase ActiveSlider. Esto ampliará EventDispatcher, apuntará a los dos clips de película en el escenario y configurará la interactividad del mouse para el comportamiento del control deslizante. Lo más emocionante de todo es que enviará un SliderEvent.

Comienza creando un nuevo archivo de clase llamado ActiveSlider.as en la carpeta com/activetuts/slider de tu proyecto. Esta clase no es demasiado intensa (al menos, no para nuestros propósitos aquí. Una clase de control deslizante podría involucrarse mucho más), y solo presentaré el código completo y discutiré a medida que avanzamos:

Nada emocionante, solo configurar el paquete e importaciones.

Necesitaremos estas tres propiedades. Los dos primeros realizan un seguimiento de los Sprites (o MovieClips) que componen el control deslizante. El tercero se utiliza mientras se arrastra la empuñadura deslizante; ayuda a mantener la posición del agarre desplazada del mouse en una cantidad relativa a dónde se hizo clic en el agarre en primer lugar.

Este es el constructor. Acepta dos argumentos sprite, que se transmiten a las dos primeras de esas propiedades para el almacenamiento. A continuación, realiza una comprobación sencilla para asegurarte de que los dos Sprites están en el mismo espacio de coordenadas comprobando que sus parent principales hacen referencia al mismo objeto. Si no lo hacen, entonces nuestras matemáticas para colocar el agarre pueden no ser confiables, por lo que lanzamos un error como una forma de alertar al desarrollador. El resto del constructor se dedica a agregar dos oyentes de eventos. El primero es un evento MOUSE_DOWN y directo. Pero el segundo es tratar de agregar un evento MOUSE_UP al Stage, que podría o no existir dependiendo de si el Sprite de grip está en la lista de visualización o no. Los siguientes dos métodos podrían hacer esto un poco más claro:

El método onAddedToStage es un agente de escucha de eventos para el evento ADDED_TO_STAGE, que se configuró en el constructor, pero solo si el Sprite de agarre no tenía ya una referencia al stage. El método addStageListener simplemente agrega el MOUSE_UP agente de escucha de eventos al strage. Por lo tanto, si hay una referencia de etapa en el constructor, llamamos a addStageListener directamente. Si no hay una referencia de stage, configuramos el evento ADDED_TO_STAGE, y cuando el agarre se agrega a la lista de visualización y, por lo tanto, tiene una referencia de stage, se activa el método onAddedToStage que, a su vez, llama a addStageListener. También elimina el ADDED_TO_STAGE oyente de eventos, porque solo necesitamos hacerlo una vez.

A continuación tenemos nuestros dos oyentes de eventos del mouse. En onDown, la línea clave es agregar un ENTER_FRAME el agente de escucha de eventos. En onUp, eliminamos ese oyente. También en onDown, tomamos nota de dónde en el agarre ocurrió realmente el clic del mouse, y lo almacenamos en _grabOffset. Esto jugará en nuestro método onFrame a continuación.

Esta es la carne principal de nuestra lógica de control deslizante. Este método se dispara repetido en un evento ENTER_FRAME, pero solo cuando el mouse ha sido presionado hacia abajo en el agarre, y solo durante el tiempo que el mouse permanezca presionado.

Primero, configuramos la propiedad x del agarre para que coincida con la posición del mouse, solo necesitamos compensarlo en función de la posición original del mouse, para que se mueva suavemente y no salte para que su borde izquierdo esté en el mouse.

Las dos líneas siguientes calculan los rectángulos delimitadores de los Sprites de agarre y de pista. Usaremos estos rectángulos en las próximas matemáticas, por lo que mantendremos las cosas más ordenados calculando previamente los rectángulos y almacenándolos en variables.

Luego está el bloque if. Esto solo restringe nuestro control deslizante dentro de la pista. Es una simple comprobación para ver si la x del agarre, como se calcula en la primera línea del método, es más baja que (a la izquierda de) la x de la pista. Si es así, sería demasiado lejos, por lo que debemos mover el agarre a ese valor mínimo. Del mismo modo, comprobamos si el borde derecho del agarre es mayor que (a la derecha de) el borde derecho de la pista, y si es así, debemos volver a enrollarlo a ese valor máximo.

Finalmente, tenemos una posición de agarre confiable, y por ahora solo rastreamos el valor actual del control deslizante, que se calcula en el bit final de código para la clase:

Este es un simple obtentor, aunque la matemática que se utiliza para el valor de retorno puede ser un poco confusa. Determina la posición de agarre actual como un porcentaje del rango de movimiento del agarre. Sería más obvio si fuera solo esto:

... Lo cual es razonable, pero no tiene en cuenta que el agarre en realidad no recorre todo el ancho de la pista. Va hasta el borde izquierdo, pero solo tan a la derecha como el borde derecho de la pista menos el ancho del agarre. Así que esto es más preciso:

Esto hace que el ancho por el cual dividimos el rango de movimiento. Sin embargo, todavía puede haber un gotcha en el que la pista puede estar desplazada a la izquierda o a la derecha de su contenedor, lo que significa que los valores que obtenemos no son del todo correctos. Necesitamos neutralizar eso restando la posición x de la pista de la x del agarre, y terminamos con esto:

Como referencia, aquí está la clase completa, con mis divagaciones omitidas:

Todavía no hemos agregado nuestra clase SliderEvent; daremos un paso aparte para hacerlo. Pero primero, necesitamos nuestra clase de documento para poder usar ActiveSlider.


Paso 21: La clase de documento

Necesitamos un archivo más para que funcione: nuestra clase de documento. Crea un nuevo archivo de clase denominado SliderDemo en la carpeta raíz del proyecto. Agrega el código siguiente:

Esto es mucho más simple que nuestra clase ActiveSlider. Realmente solo configura un ActiveSlider en la propiedad denominada _slider.

Vuelva al archivo FLA e ingrese SliderDemo en el campo de clase de documento, y deberías poder probarlo. El control deslizante debe poder moverse hacia adelante y hacia atrás, y restringirse al ancho de la pista.

Ahora para una última tarea. Necesitamos enviar y escuchar un evento SliderEvent.CHANGE. Lo haremos a continuación.


Paso 22: Envío del SliderEvent

Vuelve a la clase ActiveSlider y realiza un cambio de una sola línea en el método onFrame:

Hemos eliminado el rastro y lo hemos reemplazado con un envío de eventos real y en vivo. Sin embargo, para que esto funcione, necesitamos importar la clase SliderEvent:


Paso 23: Escuchar el SliderEvent

Finalmente, vuelve a la clase SliderDemo y cámbialo para que escuche y reaccione al SliderEvent:

Volvemos a importar la clase SliderEvent y, después de crear ActiveSlider, agregamos un agente de escucha llamado onSliderChange al control deslizante. Ese método es la mayor adición, pero sigue siendo un oyente de eventos regular. Es muy parecido a cualquier otro oyente de eventos, solo que nos aseguramos de escribir el argumento del evento como SliderEvent, porque eso es lo que estamos obteniendo.

La primera línea de código es un poco superflua, pero quería ver qué sucede cuando rastreas nuestro objeto SliderEvent. Verás, cuando ejecute esto, un formato típico para Flash del objeto de evento.

The event object represented as a StringThe event object represented as a StringThe event object represented as a String

La segunda línea hace lo que estábamos persiguiendo para empezar. Simplemente toma la propiedad sliderValue, la conviertes en string y luego pega ese string en el textField del escenario, para que podamos ver el valor del control deslizante en la película.


Paso 24: Terminando

Cuando empiezas a rodar tus propios eventos personalizados, se empieza a trabajar con ActionScript 3 de la forma en que estaba destinado a ser utilizado. Los eventos te ayudan a desacoplar las clases entre sí, y un flujo de eventos bien estructurado en tu aplicación realmente puede marcar la diferencia entre algo con lo que es fácil trabajar y algo que tiene errores y temperamental. Con esta (teóricamente) última entrega de AS3 101, deberías estar en camino de convertirte en un ninja.

¡Gracias por leer, y nos vemos aquí en Activetuts+ antes de que te des cuenta!

Advertisement
Did you find this post useful?
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.