Crear un menú de estilo Mac Dock con AS3

En este tutorial, te mostraré cómo crear un menú como el Dock de Apple usando clases AS3. Crearemos un solo archivo AS que realizará toda la magia, extendiéndolo para agregar nuevas funciones..

Tutorial republicado

Cada pocas semanas, revisamos algunas de las publicaciones favoritas de nuestros lectores de toda la historia del sitio. Este tutorial fue publicado por primera vez en marzo de 2010..


Vista previa del resultado final

Primero, echemos un vistazo a lo que vamos a crear. Pase el mouse sobre los íconos para ver cómo se mueven y escalan.


Paso 1: crear un nuevo archivo de ActionScript

Comience por crear un nuevo archivo ActionScript y guárdelo como "DockItem.as". Estoy guardando la mía en c: /macmenu/org/effects/DockItem.as.

Tenga en cuenta que la raíz de nuestro documento (donde vive .fla) será c: / macmenu; la carpeta / org / effects formará el paquete para la clase DockItem.


Paso 2: Crea una nueva FLA

Cree un nuevo archivo Flash ActionScript 3.0 y ábralo, para que tengamos tanto DockItem.as como este archivo .fla abierto. Guarde este archivo .fla en la carpeta raíz (DockItem.as está en c: / macmenu / org / effects, por lo que nuestra raíz del sitio es c: / macmenu) / org / effects es el paquete de DockItem Object y guardamos el archivo. fla como c: /macmenu/macmenu.fla.


Paso 3: Importar iconos

Ahora importamos o dibujamos algunos iconos al .fla. He importado algunos iconos que tengo aquí desde un archivo de Illustrator, pero, por supuesto, puedes dibujar los tuyos y aplicarles un degradado..


Paso 4: Comience a convertir íconos en símbolos

Seleccione cualquier icono y haga clic en Modificar> Convertir en símbolo.

En el cuadro que se abre, asígnele un nombre (llamé a este símbolo "Estrella") y preste atención al punto de registro; tiene que ser el centro inferior. Para la clase, use el mismo nombre (recuerde que no puede usar espacios) y para la clase Base, use org.effects.DockItem (la clase que crearemos). Además, asegúrese de que su Tipo esté configurado en Clip de película.

Luego, alinee todos los objetos en la parte inferior: seleccione todos, haga clic en Ventana> Alinear, asegúrese de que el botón "Al escenario" no esté seleccionado (de lo contrario, se alineará en la parte inferior del escenario), luego haga clic en el botón superior derecho en este Panel para alinear todos los objetos..


Paso 5: Convertir todos los iconos en símbolos

Podemos tener tantos botones como queramos, así que vamos a convertir todos nuestros íconos en símbolos. Recuerde darles un nombre y una clase, establecer todos sus puntos de registro en la parte inferior central y establecer la clase base en org.effects.DockItem.

Vea a continuación cómo se ven nuestra biblioteca y los íconos; tenga en cuenta el espacio entre ellos, es importante para crear un buen efecto.


Paso 6: Comience a codificar la clase DockItem

Si probamos la película ahora, se producirá un error que indica que un archivo ActionScript debe tener al menos una definición externa y visible; eso se debe a que todos los elementos de nuestro menú están extendiendo la clase DockItem, que aún no hemos escrito. Vamos a escribirlo ahora ...

Comience a crear el paquete extendiendo la clase Sprite (extenderemos Sprite ya que no tenemos una animación de línea de tiempo).

 package org.effects import flash.display.Sprite; clase pública DockItem extiende Sprite 

En este punto tenemos nuestro DockItem extendiendo la clase Sprite, así que si lo pruebas ahora funcionará, pero no verás efectos.

(¿Confuso? ¿No está acostumbrado a codificar con clases? Consulte este Consejo rápido sobre el uso de una clase de documento para una introducción.)


Paso 7: Importar Clases Necesarias

Ahora vamos a importar todas las clases necesarias. Aquí se está utilizando una clase personalizada, la clase TweenLite, que puede descargar desde GreenSock.com. Cuando hayas descargado TweenLite, extráelo a tu carpeta / macmenu / (para que tengas una carpeta / macmenu / com / greensock /).

 package org.effects import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import com.greensock.TweenLite; //http://www.greensock.com/tweenlite import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; clase pública DockItem extiende Sprite 

He importado la clase Sprite porque es lo que estamos extendiendo; Si tiene animaciones en la línea de tiempo, extienda la clase MovieClip. Usaremos la clase Evento cuando el objeto personalizado se agregue a la etapa y usaremos MouseEvent al verificar la distancia de cada icono desde el mouse.


Paso 8: Declara las variables necesarias

Durante este paso declararemos las variables necesarias:

 package org.effects import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; clase pública DockItem extiende Sprite private var _initPosition: Number; public var maxXDistance: Number; public var maxYDistance: Number; public var maxScale: Number; 

Tenga en cuenta que he usado el _initPosition como privado: solo establece la posición x inicial del icono. La distancia del mouse siempre se medirá desde este punto, porque la posición x real del elemento siempre estará cambiando.

maxXDistance es la distancia x máxima sobre la cual el mouse afectará el ícono, distancia máxima es la distancia y máxima sobre la cual el mouse afectará el ícono y maxScale es la escala máxima que se agregará al icono (por ejemplo, si lo establece en 2, la escala máxima que puede alcanzar el objeto es 3).

He usado variables públicas para los últimos tres para que podamos cambiarlas en tiempo de ejecución.


Paso 9: Codificando la Función Constructora

La función constructora debe tener el mismo nombre que la clase (y por lo tanto el mismo nombre que el archivo), por lo tanto DockItem ():

 package org.effects import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; clase pública DockItem extiende Sprite private var _initPosition: Number; public var maxXDistance: Number; public var maxYDistance: Number; public var maxScale: Number; función pública DockItem ($ maxXDistance: Number = 60, $ maxYDistance: Number = 30, $ maxScale: Number = 2): void maxXDistance = $ maxXDistance; maxYDistance = $ maxYDistance; maxScale = $ maxScale; if (stage) init (); else addEventListener (Event.ADDED_TO_STAGE, init); addEventListener (Event.REMOVED_FROM_STAGE, final); 

¿Por qué tenemos algunos parámetros aquí? Esto nos permite utilizar diferentes combinaciones de distancias y escalas: podemos tener una distancia corta con una escala muy grande o una distancia larga con una escala pequeña. Además, podemos determinar la distancia y dentro de la cual el mouse afectará el ícono.

A medida que ampliamos la clase Sprite, podemos agregar hijos o incluso codificar una clase personalizada para cada icono que extiende la clase DockItem, por lo que si lo ampliamos podemos usar la función super () para pasar los nuevos parámetros a la superclase. Podemos usar la clase DockItem en cualquier momento y en cualquier lugar.

En este paso, configuramos la variable maxXDistance, la variable maxYDistance y la variable maxScale a los valores pasados ​​como parámetros. Además, verificamos si el objeto está en el escenario; si no, agregamos un Evento para verificar cuándo está. También agregamos otro detector de eventos para detectar cuándo se elimina el icono del escenario. Agregaremos un evento MOUSE_MOVE al escenario para obtener la distancia, por lo que es importante saber si está en el escenario..


Paso 10: La función Init ()

Esta es la función que se ejecutará una vez que el icono se haya creado y agregado al escenario. En la función init () solo agregamos un detector MouseEvent.MOUSE_MOVE al escenario, configuramos la variable _initPosition al valor x del objeto y escuchamos el mouse que abandona el área del escenario.

 package org.effects import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; clase pública DockItem extiende Sprite private var _initPosition: Number; public var maxXDistance: Number; public var maxYDistance: Number; public var maxScale: Number; función pública DockItem ($ maxXDistance: Number = 60, $ maxYDistance: Number = 30, $ maxScale: Number = 2): void maxXDistance = $ maxXDistance; maxYDistance = $ maxYDistance; maxScale = $ maxScale; if (stage) init (); else addEventListener (Event.ADDED_TO_STAGE, init); addEventListener (Event.REMOVED_FROM_STAGE, final);  función privada init (e: Evento = nulo): void _initPosition = x; stage.addEventListener (MouseEvent.MOUSE_MOVE, mouseMove); stage.addEventListener (Event.MOUSE_LEAVE, mouseLeave); 

Paso 11: Las funciones del ratón

Cuando el mouse se mueve sobre el escenario, esta función (activada por el evento MOUSE_MOVE que agregamos un oyente en el último paso) verificará la posición del mouse del objeto principal y medirá la distancia desde el objeto hasta la posición del mouse principal..

Usamos parent.mouseX porque eso nos da la posición x del mouse en relación con el objeto que contiene el ícono, en lugar de hacerlo con el punto de registro del ícono.

También volvemos a interpolar los iconos a sus posiciones iniciales si el mouse deja el escenario en el controlador mouseLeave ()..

 package org.effects import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; clase pública DockItem extiende Sprite private var _initPosition: Number; public var maxXDistance: Number; public var maxYDistance: Number; public var maxScale: Number; función pública DockItem ($ maxXDistance: Number = 60, $ maxYDistance: Number = 30, $ maxScale: Number = 2): void maxXDistance = $ maxXDistance; maxYDistance = $ maxYDistance; maxScale = $ maxScale; if (stage) init (); else addEventListener (Event.ADDED_TO_STAGE, init); addEventListener (Event.REMOVED_FROM_STAGE, final);  función privada init (e: Evento = nulo): void _initPosition = x; stage.addEventListener (MouseEvent.MOUSE_MOVE, mouseMove); stage.addEventListener (Event.MOUSE_LEAVE, mouseLeave);  función privada mouseMove (e: MouseEvent): void var yDistance: Number = Math.abs (parent.mouseY-y); if (yDistance> maxYDistance) if (_initPosition == x) devuelve; else TweenLite.to (this, .3, x: _initPosition, scaleX: 1, scaleY: 1); regreso;  // obtener la diferencia entre la posición x del mouse principal y la posición inicial del objeto var xDistance: Number = parent.mouseX-_initPosition; // comprueba si la distancia del ratón al objeto es mayor que la distancia máxima, no puede ser más grande ... xDistance = xDistance> maxXDistance? MaxXDistance: xDistance; // comprueba si la distancia es menor que el negativo de la distancia máxima, no puede ser menor ... xDistance = xDistance < -maxXDistance ? -maxXDistance : xDistance; //create a variable for the position, assuming that the x position must be the initial position plus the distance of the mouse, but it can't be more than the max distance. var posX=_initPosition-xDistance; //we get the scale proportion here, it goes from 0 to maxScale variable var scale:Number=(maxXDistance-Math.abs(xDistance))/maxXDistance; //the minimum scale is 1, the original size, and the max scale will be maxScale variable + 1 scale=1+(maxScale*scale); //here we use a Tween to set the new position according to the mouse position TweenLite.to(this,.3,x:posX,scaleX:scale,scaleY:scale);  private function mouseLeave(e:Event):void TweenLite.to(this,.3,x:_initPosition,scaleX:1,scaleY:1);   

Primero, verificamos la distancia y (distancia vertical entre el icono y el mouse); si está más lejos que el rango que establecimos con maxYDistanceVariable, luego verificamos si el ícono está nuevamente en su posición original y, si no, lo interpolamos allí. los regreso la palabra clave se sale de la función, por lo que no se ejecutará nada del resto del código en este caso.

Si el mouse está cerca del ícono verticalmente, usamos algunos cálculos matemáticos para descubrir una nueva escala y posición para el ícono en base a su distancia horizontal del mouse, luego lo interpolamos a esos valores.


Paso 12: La Función Fin ()

Si eliminamos el objeto del escenario, debemos eliminar los escuchas mouseMove y mouseLeave; Si no, podemos obtener errores cada vez que se mueve el mouse. Esta función es el controlador para el escucha REMOVED_FROM_STAGE que agregamos anteriormente, por lo que se activará cuando se elimine el objeto..

 package org.effects import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; clase pública DockItem extiende Sprite private var _initPosition: Number; public var maxXDistance: Number; public var maxYDistance: Number; public var maxScale: Number; función pública DockItem ($ maxXDistance: Number = 60, $ maxYDistance: Number = 30, $ maxScale: Number = 2): void maxXDistance = $ maxXDistance; maxYDistance = $ maxYDistance; maxScale = $ maxScale; if (stage) init (); else addEventListener (Event.ADDED_TO_STAGE, init); addEventListener (Event.REMOVED_FROM_STAGE, final);  función privada init (e: Evento = nulo): void _initPosition = x; stage.addEventListener (MouseEvent.MOUSE_MOVE, mouseMove); stage.addEventListener (Event.MOUSE_LEAVE, mouseLeave);  función privada mouseMove (e: MouseEvent): void var yDistance: Number = Math.abs (parent.mouseY-y); if (yDistance> maxYDistance) if (_initPosition == x) devuelve; else TweenLite.to (this, .3, x: _initPosition, scaleX: 1, scaleY: 1); regreso;  // obtener la diferencia entre la posición x del mouse principal y la posición inicial del objeto var xDistance: Number = parent.mouseX-_initPosition; // comprueba si la distancia del ratón al objeto es mayor que la distancia máxima, no puede ser más grande ... xDistance = xDistance> maxXDistance? MaxXDistance: xDistance; // comprueba si la distancia es menor que el negativo de la distancia máxima, no puede ser menor ... xDistance = xDistance < -maxXDistance ? -maxXDistance : xDistance; //create a variable for the position, assuming that the x position must be the initial position plus the distance of the mouse, but it can't be more than the max distance. var posX=_initPosition-xDistance; //we get the scale proportion here, it goes from 0 to maxScale variable var scale:Number=(maxXDistance-Math.abs(xDistance))/maxXDistance; //the minimum scale is 1, the original size, and the max scale will be maxScale variable + 1 scale=1+(maxScale*scale); //here we use a Tween to set the new position according to the mouse position TweenLite.to(this,.3,x:posX,scaleX:scale,scaleY:scale);  private function mouseLeave(e:Event):void TweenLite.to(this,.3,x:_initPosition,scaleX:1,scaleY:1);  private function end(e:Event=null):void stage.removeEventListener(MouseEvent.MOUSE_MOVE,mouseMove); stage.removeEventListener(Event.MOUSE_LEAVE,mouseLeave);   

Todo lo que hacemos en esta función es eliminar el detector de eventos del escenario..


Paso 13: Pruébalo!

En este punto ya podemos probarlo; funcionará ya que cada objeto está vinculado con la clase Base DockItem. Sin embargo, no tenemos un cuadro de límite para hacer clic (si configuramos el objeto buttonMode propiedad a true, veremos que podemos hacer clic solo cuando está sobre el gráfico real.)


Paso 14: Comience a convertir los iconos en botones

Hasta ahora podemos ver el efecto en funcionamiento, así que ahora vamos a convertir cada elemento en un botón. Crearemos un nuevo archivo de ActionScript y este extenderá el DockItem, llamémoslo DockButton. Su paquete será el mismo que DockItem (org.effects), por lo que guardaremos itb en la misma carpeta que DockItem.as (ejemplo: c: /macmenu/org/effects/DockButton.as)


Paso 15: Cambiar la clase base

Ahora cambiamos la clase base de cada objeto en la biblioteca. Actualmente estamos usando org.effects.DockItem como clase base, ahora vamos a usar org.effects.DockButton.

Si lo probamos ahora, habrá un error. Esto se debe a que DockButton.as todavía está vacío, así que vamos a codificarlo.


Paso 16: Iniciar la codificación DockButton.as

Bien, ahora extenderemos la clase DockItem, porque queremos usar todo lo que tenemos en DockItem y agregar algunos trucos más (permitiéndole actuar como un botón), pero no queremos agregar las nuevas funciones a DockItem directamente. De esta manera, si queremos usar el DockItem como algo que no sea un botón más adelante, podemos hacerlo, pero si queremos usarlo como un botón podemos usar el DockButton.

 paquete org.effects clase pública DockButton extiende DockItem 

Si probamos nuestro proyecto ahora, funcionará, pero funcionará exactamente como DockItem ya que aún no hemos agregado nada nuevo..


Paso 17: Importar clases para DockButton

Importemos algunas cosas que necesitaremos para extender el DockItem. Como estamos extendiendo el DockItem, no necesitamos importar las clases que ya existen, ya que no las usaremos directamente en DockButton.

 paquete org.effects import flash.geom.Rectangle; clase pública DockButton extiende DockItem 

He importado la clase Rectangle, pero ¿por qué? Es porque usaremos el cuadro delimitador de nuestro objeto para crear un fondo falso, para permitir que se pueda hacer clic en el botón, incluso si el mouse no está precisamente sobre un área coloreada. Vamos a crear un gráfico de fondo con alfa 0 (transparente), para que tengamos un cuadrado para hacer clic.


Paso 18: Constructor para DockButton

Ya que necesitamos crear un cuadro delimitador para DockButton, obtendremos sus propios límites, por eso importamos la clase flash.geom.Rectangle

 paquete org.effects import flash.geom.Rectangle; la clase pública DockButton extiende DockItem public function DockButton (): void buttonMode = true; mouseChildren = falso; var lines: Rectangle = getBounds (this); this.graphics.beginFill (0,0); this.graphics.drawRect (límites.x, límites.y, límites.width, límites.height); this.graphics.endFill (); 

¿Lo que hemos hecho? Creamos un constructor que primero establece el modo de botón del objeto en verdadero, por lo que nuestro DockButton se tratará como un botón. Luego establecemos mouseChildren en falso, por lo que los eventos del mouse provendrán del objeto DockButton, no de ningún otro objeto dentro de él. A continuación, obtenemos los límites del objeto utilizando getBounds () y dibujamos un rectángulo transparente utilizando el objeto de gráficos. (La propiedad de gráficos viene con la clase Sprite, y extendimos Sprite para hacer nuestro objeto DockItem. Ahora hemos extendido nuestro DockItem para hacer nuestro objeto DockButton, DockButton tiene todo, desde la clase Sprite y la clase DockItem.)


Paso 19: Comprueba todo y pruébalo

OK, vamos a realizar una comprobación:

  • Necesitamos un archivo .fla (ejemplo: c: /macmenu/macmenu.fla).
  • En la misma carpeta que el archivo .fla, necesitamos tener otra carpeta: / org / effects (ejemplo: c: / macmenu / org / effects).
  • Dentro de esta carpeta necesitamos tener dos documentos .as (DockItem.as y DockButton.as)
  • Dentro de .fla, cada elemento de la biblioteca debe estar vinculado a una clase, y la clase base de cada elemento debe ser org.effects.DockButton.

Si todo está bien, prueba la película ...

(En este punto, si desea poner la carpeta org / effects en su ruta de clases, puede hacerlo, por lo que no tendrá que copiar esta carpeta en cada proyecto que cree y use DockItem o DockButton).


Paso 20: Cambia el color al pasar el mouse

¿Por qué no cambiar el color del botón cuando el mouse pasa sobre él? En esta sección enseñaré cómo. Para esto usaremos el motor TweenLite nuevamente para darle un poco de tinte al objeto. Sin embargo, ya estamos utilizando TweenLite en el objeto DockItem y estamos extendiendo este objeto en DockButton. Queremos extender DockButton para cambiar el color, pero ya no podemos usar TweenLite en el mismo objeto ya que el nuevo objeto TweenLite sobrescribirá al otro (incluso con la propiedad sobrescribir: falso en TweenLite reducirá mucho el rendimiento si lo usamos directamente en el mismo objeto). No todo está perdido; tenemos un icono dentro de cada objeto de la biblioteca y podemos aplicar el tinte a ese.

Para hacer esto, vamos a crear otro archivo ActionScript, pero ahora guárdelo en la misma carpeta que .fla con el nombre "OverButton.as" (ejemplo: c: /macmenu/OverButton.as).


Paso 21: Codificar el objeto OverButton

Primero creamos el paquete e importamos las clases necesarias; ya que guardamos el archivo OverButton.as en la misma carpeta del archivo .fla, el paquete será de nivel superior, por lo que no es necesario escribir "package org.effects":

 package import org.effects.DockButton; importar flash.display.DisplayObject; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; La clase pública OverButton extiende DockButton 

Bien, estamos extendiendo DockButton esta vez y hemos importado la clase DisplayObject porque trataremos el icono como un DisplayObject. También hemos importado MouseEvent que usaremos para verificar cuándo el mouse está sobre el ícono y cuando está fuera. También tenemos TweenLite para crear algunos efectos de interpolación con el color..


Paso 22: OverButton Constructor

 package import org.effects.DockButton; importar flash.display.DisplayObject; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; la clase pública OverButton extiende DockButton private var _object: DisplayObject; función pública OverButton (): void _object = this.getChildAt (0) como DisplayObject; this.addEventListener (MouseEvent.MOUSE_OVER, mouseOver); this.addEventListener (MouseEvent.MOUSE_OUT, mouseOut); TweenPlugin.activate ([TintPlugin]); 

¿Por qué hemos creado una var _object privada como DisplayObject? Nuestro icono real se almacena en esta variable (eso es lo que hace la línea 13) y se trata como un objeto de visualización (DisplayObject); Usaremos el efecto de color en nuestro icono, no en todo el objeto..

Agregamos los detectores de eventos del mouse para verificar cuándo el mouse está sobre y cuando el mouse está fuera..


Paso 23: Codificación de las funciones del ratón

Ya que hemos creado los oyentes para el mouse over y mouse out, ahora crearemos sus funciones:

 package import org.effects.DockButton; importar flash.display.DisplayObject; import flash.events.MouseEvent; import com.greensock.TweenLite; import com.greensock.plugins.TweenPlugin; import com.greensock.plugins.TintPlugin; la clase pública OverButton extiende DockButton private var _object: DisplayObject; función pública OverButton (): void _object = this.getChildAt (0) como DisplayObject; this.addEventListener (MouseEvent.MOUSE_OVER, mouseOver); this.addEventListener (MouseEvent.MOUSE_OUT, mouseOut); TweenPlugin.activate ([TintPlugin]);  función privada mouseOver (e: MouseEvent): void new TweenLite (_object, .5, tint: 0x990099);  función privada mouseOut (e: MouseEvent): void new TweenLite (_object, .5, tint: null); 

Tenga en cuenta que estamos utilizando TweenLite en _object ahora, no en "esto" más. Esto se debe a que OverButton extiende el DockButton que extiende el DockItem donde ya se está utilizando un TweenLite. Además, en DockButton tenemos un fondo falso alfa 0 que no necesita ser pintado.

Para la propiedad de tinte de TweenLite usé un código de color de 0x990099, que es un púrpura medio; Si utiliza nulo como valor, el tinte se eliminará suavemente..


Paso 24: Cambiar las clases base

En este punto, si prueba la película, no verá ningún cambio de color, porque necesitamos cambiar la clase base de cada objeto en la biblioteca nuevamente. Abra la Biblioteca una vez más en .fla (Ventana> Biblioteca). Haga clic derecho en cada objeto y cambie su clase base a OverButton (no org.effects.OverButton, porque el archivo de clase no está en la carpeta / org / effects).

OK, ahora puedes probarlo!

Conclusión

En este tutorial he explicado cómo extender objetos. El efecto de acoplamiento real es matemática pura: cálculos de distancia, configuraciones de escala, pero es importante que veamos en el código que no podemos usar la propiedad "x" como referencia de posición, porque la propiedad "x" cambia cada vez. Espero que ahora todos ustedes tengan un mejor entendimiento de la palabra clave "extiende" y puedan apreciar cómo se realizan los cálculos aquí. Gracias por leer :)