A veces solo quieres ser muy moderno con tu sitio web. ¿Y qué mejor manera de mostrar a las personas lo genial que eres como programador flash que hacer que ellos lo experimenten ellos mismos? En este tutorial, te mostraré cómo crear un menú moderno con botones tipo resorte. Incluso lo haremos personalizable desde xml.!
Echemos un vistazo rápido a lo que estamos trabajando:
Cree un nuevo archivo flash ActionScript 3 y configure las dimensiones en 600 x 200 píxeles. Estamos configurando estas dimensiones para tener espacio para que los botones sigan el mouse. Establezca la velocidad de fotogramas en 25 y el DocumentClass en ElasticMenu, Una clase que crearemos después del diseño..
Vamos a hacer un gradiente de fondo que será la base de nuestro botón. Crea un rectángulo y hazlo de 150 x 40 px. El tamaño no importa en este momento, porque cambiaremos el tamaño del rectángulo para que coincida con el tamaño del texto del botón.
Puedo escucharte preguntando: ¿por qué no crear un rectángulo programáticamente con Sprite.graphics.drawRectangle ()? Te mostraré por qué elegí este camino. La razón detrás de hacer un clip de película en el escenario es que podemos cortar el rectángulo para crear un botón de recorte como en esta vista previa:
No voy a hablar sobre cómo hacer este ejemplo aquí, pero este método es mejor en caso de que quiera darle un toque especial al fondo del botón. Eso es solo un consejo.
Seleccione el rectángulo que acaba de crear y presione F8 (Modificar> Convertir a símbolo) para hacer el gráfico de fondo y marque Exportar para ActionScript. Dale a este movieclip el nombre de la clase "GradBackground". Utilizaremos este nombre de clase de ActionScript.
Ahora crearemos el archivo xml para mantener nuestra configuración. De este archivo, la película flash obtendrá el nombre del botón, la ubicación del enlace y el color. Cree un nuevo archivo junto a la fuente .fla y asígnele un nombre menu.xml con lo siguiente:
¿Qué pasa aquí? Estamos creando un
Ahora vamos a construir el menú flash actual. Cree un nuevo archivo ActionScript y asígnele un nombre ElasticMenu.as. Para la velocidad, he usado el comodín * para importar todas las clases en el paquete. Después de terminar el menú flash, puede modificar las importaciones para incluir solo lo que necesita, para reducir el tamaño del archivo. Crea el paquete habitual y el nombre de la clase. ElasticMenu con las variables requeridas:
paquete import flash.display. *; importar flash.text. *; importar flash.net. *; importar flash.events. *; import flash.utils.Timer; la clase pública ElasticMenu extiende MovieClip var xml: XML; botones var: Array; var tm: temporizador; var maxdist: Número = 50;
los xml variable mantendrá el xml real cargado desde el menu.xml expediente. los botones Variable es una matriz que contendrá las referencias de los botones..
los tm Es un temporizador que se encargará del control real de la distancia..
los maxdist la variable definirá a qué distancia se separará el botón del mouse y regresará a su lugar.
Ok, vamos a crear la función constructora, agregar las operaciones de carga y procesar el xml:
función pública ElasticMenu () var req = new URLLoader (); req.addEventListener (Event.COMPLETE, xml_loaded); req.load (nueva URLRequest ('menu.xml')); botones = nueva matriz (); tm = nuevo temporizador (40); tm.addEventListener (TimerEvent.TIMER, check_buttons); función privada xml_loaded (e: Event) xml = XML (e.target.data); createButtons ();
¿Que esta pasando aqui? Creamos un objeto URLRequest y agregamos un controlador de eventos completo que activará la función xml_loaded cuando se carga el xml.
Iniciamos el botones array y el temporizador, y vinculamos el evento TIMER al Botones check () función. Esta es la función que comprobará la distancia de los botones. Una vez cargado el xml, lo pasamos a la xml variable y construir los botones con el crearBotones () Función, la cual crearemos a continuación..
Continúe creando los botones y colóquelos en el escenario programáticamente:
función pública createButtons () var sectw = (stage.stageWidth / (xml… button.length () + 1)); para (var i = 0; i< xml… button.length(); i++) var m = new ElasticButton(); m.x = sectw + (sectw*i); m.y = stage.stageHeight/2; m.init( xml… button[i] ); addChild( m ); buttons.push( m ); tm.start();
Ok, entonces estamos definiendo la secta variable, que es la etapa dividida en el número de botones más uno. ¿Por qué? Porque organizaremos los botones para que estén exactamente a la misma distancia entre sí y ocupen todo el ancho del escenario. Para entender mejor esto, mira la siguiente imagen:
Como estamos centrando los botones en los ejes x e y, terminarán estando a distancias iguales entre sí. Luego estamos creando un bucle for, en el que definimos cada botón como un nuevo ElasticButton Clase, que codificaremos en breve. Colocamos cada botón en secta Distancia unos de otros y establecer su y a la mitad del escenario para centrarlos. Luego los agregamos al escenario y los insertamos en la matriz de botones, para su uso posterior. Pero hay otra función que llamamos en el botón que definiremos en la clase ElasticButton, en la cual pasamos el nodo del botón xml actual.
Continuemos con la función principal activada cada 40 milisegundos por el temporizador:
función privada check_buttons (e: TimerEvent) para (var b en botones) if (botones [b] .dragging) botones [b] .x = mouseX; botones [b] .y = mouseY; if (buttons [b] .getDistance ()> maxdist) buttons [b] .reset ();
Ok, vamos a explicar rápidamente lo que está pasando aquí para poder pasar a la clase ElasticButton:
En primer lugar, recorremos todos los botones de la matriz y, para cada uno, verificamos si tienen una propiedad de arrastre con el valor "verdadero". Básicamente, si el mouse está sobre el botón y "sí", verificamos si getDistance () método de la ElasticButton la clase es más alta que la maxdist variable. Si es más alto, llamamos a Reiniciar() Función en el botón. Aún no sabemos nada de estas funciones..
OK, finalmente, la clase que todos hemos estado esperando, la clase de botones. Aquí es donde suceden todas las cosas importantes: averiguar la distancia, crear el texto, el fondo y las llamadas Reiniciar() para devolver el botón a su ubicación.
paquete import flash.display. *; importar flash.text. *; importar flash.net. *; importar flash.events. *; importar flash.geom.ColorTransform; importar fl.transitions.Tween; importar fl.transitions.TweenEvent; importar fl.transitions.easing. *; importar fl.motion.Color; la clase pública ElasticButton extiende MovieClip var origin: Object; campo de texto var: TextField; var tf: TextFormat; var arrastrando: Booleano = falso; var bg: Sprite; var url: String; var twx: Tween; var twy: Tween; Acolchado var: Número = 8; color var: uint; var msk: Sprite; función pública ElasticButton () // no hacer nada
Déjame explicarte las líneas:
Encontrará que además de importar las clases normales, también importamos fl.transitions.Tween y TweenEvent, easing y las clases fl.motion.Color. Necesitamos las clases de interpolación para volver a interpolar la película a su origen y la clase de color para matizar el fondo del color en el xml..
Aquí tenemos un par de variables:
los origen objeto es un objeto que mantendrá las posiciones x e y del botón. Podría haberlo convertido en un objeto flash.geom.Point pero soy demasiado vago para incluir otra clase para 2 variables!
Tenemos una campo de texto variable que mantendrá el campo de texto etiqueta de botón, el tf variable que es un objeto TextFormat para el estilo de texto, el conocido arrastrando propiedad, un bg var, que será el movieclip de fondo, una cadena con la url para el botón, dos variables para mantener las interpolaciones, una relleno variable que hará el botón un poco más grande, el color objeto y un msk Var, que será una máscara para el movieclip. Necesitamos esto para hacer la esquina redondeada que viste en la vista previa!
Hagamos la función init, activada por nuestra clase padre:
función pública init (node) textfield = new TextField (); tf = nuevo TextFormat (); tf.size = 14; tf.font = '_sans'; tf.bold = verdadero; tf.color = 0xffffff; tf.align = TextFormatAlign.CENTER; textfield.defaultTextFormat = tf; textfield.text = nodo ... nombre; textfield.width = 65; textfield.height = 20; textfield.x = - (textfield.width / 2); textfield.y = - (textfield.height / 2); textfield.mouseEnabled = false; addChild (campo de texto); origen = nuevo objeto (); origin.x = this.x; origen.y = este.y; color = nodo ... color; crearBG (); url = nodo ... url; arrastrando = falso; this.buttonMode = true; this.addEventListener (MouseEvent.MOUSE_OVER, mouse_over); this.addEventListener (MouseEvent.CLICK, mouse_click);
Ya hay mucho!
Creamos el campo de texto, le asignamos un formato de texto con ciertas propiedades (no entraré en detalles aquí), establecemos el color en blanco, ya que los fondos tienden a ser más oscuros, le damos el texto del nodo pasado como parámetro . Bastante estandar.
Es mejor crear un ancho y alinear el texto al centro para que las diferentes palabras queden perfectamente alineadas. Solo debes asegurarte de no incluir una palabra muy larga, o el botón se verá feo!
A continuación tenemos un interesante posicionamiento del campo de texto. Establecemos la x en menos la mitad del ancho y la y en la mitad del alto del campo de texto, alineando el campo de texto exactamente en el centro. Necesitamos esto para tener un cálculo uniforme de la distancia máxima..
Nosotros fijamos ratón habilitado a falso para el campo de texto, para desactivar el mouse deslizando el botón. Busqué esta propiedad para una todo el dia cuando empecé AS3 por primera vez :)
los origen el objeto se inicializa a continuación y creamos las propiedades x e y con las xey del movieclip actual (la clase ElasticButton). Cuando el botón va más allá del maxdist, devolveremos el botón a estos puntos de origen.
Hay un par de cosas más que están sucediendo aquí: tenemos el color del nodo xml en el color var, mantenemos la url del botón en el url var amd llamamos un crearBG () Función que aún no hemos codificado..
Configuramos el arrastre a falso, buttonMode para el ElasticButton actual a verdadero y creamos el mouse sobre y hacemos clic en los controladores.
Esta función se encargará de hacer el fondo y teñirlo de acuerdo con el color en el xml:
función pública createBG () bg = new GradBackground (); var dbpad = relleno * 2; bg.width = textfield.width + dbpad; bg.height = textfield.height + dbpad; bg.x = - ((textfield.width + dbpad) / 2); bg.y = - ((textfield.height + dbpad) / 2); addChild (bg); var col = nuevo Color (1,1,1,1); col.setTint (color, 0.4); bg.transform.colorTransform = col; setChildIndex (bg, 0);
Aquí hacemos una clase de GradBackground, que es el movieclip que creamos en el código fuente y le damos el nombre de clase GradBackground. Establecemos el ancho y alto del movieclip al ancho del campo de texto más una variable dbpad. Notará que definí esta variable para la velocidad, de modo que no escriba (relleno * 2). Definir una nueva variable con el doble relleno precomputado es más rápido que llamar a esta operación muchas veces. También tenemos que ocuparnos de la CPU.!
¿Por qué estoy agregando una variable de relleno? Para que el botón sea más grande que el campo de texto. Mira esta imagen para obtener una mejor comprensión:
También estoy centrando el movieclip bg como lo hice con el campo de texto: configuré la x en menos la mitad de la altura y menos la mitad del ancho del movieclip bg.
A continuación, creo un nuevo Color con atributos predeterminados (rgb y alpha 1) y luego uso el setTint() función para hacer que sea un tono del color xml. Debido a que la clase Color es una subclase de la clase ColorTransform, podemos pasar este color directamente al objeto transformi.colorTransform de movieclip..
Por último, configuramos bi movieclip la profundidad 0, por lo que todo estará por encima del fondo.
Voy a ir rápidamente a través de los controladores de eventos:
función privada mouse_over (e: MouseEvent) dragging = true; función privada mouse_click (e: MouseEvent) navigationToURL (new URLRequest (url));
Los controladores de eventos son bastante simples: configuro el arrastre a verdadero cuando el mouse se desplaza sobre el botón. Para el controlador de clic utilizo el navigationToURL () Función para ir a la url solicitada. Si está construyendo un sitio flash, aquí es donde irá la acción para el cambio de página.
Esta es la función más importante en el menú. Recuerda, estamos llamando al getDistance funciona para ver si es más grande que el maxdist var para que podamos restablecer el boton Estamos utilizando la ecuación algebraica de Pitagora para encontrar la distancia entre 2 puntos:
función pública getDistance () return Math.sqrt ((this.x-origin.x) * (this.x-origin.x) + (this.y-origin.y) * (this.y-origin.y) );
Esto nos dará la distancia entre los botones x e y y el origen x e y. Por eso mantenemos la variable de origen..
Esta función se activa cuando la distancia desde el origen es demasiado alta. En ese punto volvemos a interpolar el botón a su origen:
función pública reset () arrastrando = falso; twx = new Tween (this, 'x', Elastic.easeOut, this.x, origin.x, 0.4, true); twy = new Tween (this, 'y', Elastic.easeOut, this.y, origin.y, 0.4, true);
Establecemos el arrastre a falso y creamos dos interpolaciones; uno para la x y otro para la y. Podríamos haber utilizado otra biblioteca de interpolación, usar solo una interpolación y pasar una matriz a la función de interpolación, pero la clase de interpolación incorporada de AS3 no admite varias propiedades, por lo que yo sé.
Permítame mostrarle, como bonificación, cómo hacer la primera y la última ronda de botones, como vio en la vista previa. Creamos una nueva función. makeStartButton () donde construiremos la máscara redondeada:
función pública makeStartButton () msk = new Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.moveTo (0, relleno); msk.graphics.curveTo (0, 0, relleno, 0); msk.graphics.lineTo ((relleno * 2) + textfield.width, 0); msk.graphics.lineTo ((padding * 2) + textfield.width, (padding * 2) + textfield.height); msk.graphics.lineTo (0, (relleno * 2) + textfield.height); msk.graphics.lineTo (0, relleno); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (msk); bg.mask = msk;
Ok, esto tiene que ser explicado:
Creamos un nuevo Sprite y utilizamos la clase de gráficos. beginFill () Para hacer un relleno, el color no importa. Para entender lo que está pasando, veamos esta imagen:
Construimos la máscara de fondo redondeada y la agregamos a la lista de visualización, configurándola como una máscara para la bg movieclip
Usamos el mismo procedimiento, ahora con la curva a la derecha:
función pública makeEndButton () var dbpad = padding * 2; msk = nuevo Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.lineTo (textfield.width + padding, 0); msk.graphics.curveTo (textfield.width + dbpad, 0, textfield.width + dbpad, relleno); msk.graphics.lineTo (dbpad + textfield.width, dbpad + textfield.height); msk.graphics.lineTo (0, dbpad + textfield.height); msk.graphics.lineTo (0, relleno); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (msk); bg.mask = msk;
Verás que es la misma técnica, solo hacemos la curva a la derecha y agregamos la máscara a la bg movieclip.
Necesitamos modificar la clase ElasticMenu para llamar a estas dos funciones en los botones primero y último. En los createButtons () hacemos las siguientes modificaciones (líneas 8 - 13):
función pública createButtons () var sectw = (stage.stageWidth / (xml… button.length () + 1)); para (var i = 0; i< xml… button.length(); i++) var m = new ElasticButton(); m.x = sectw + (sectw*i); m.y = stage.stageHeight/2; m.init( xml… button[i] ); if( i == 0 ) m.makeStartButton(); if( i == xml… button.length()-1) m.makeEndButton(); addChild( m ); buttons.push( m ); tm.start();
Así que si la variable yo es 0 (si es el primer botón) o si yo es el xml… button.length () - 1 (Si es la última) llamamos a la función respectiva..
Solo recuerde, si encuentra algún error, que las funciones que llamamos de la clase padre, ElasticMenu tiene que ser público en el ElasticButton clase, de lo contrario obtendrá un error que la función no existe!
¡Eso es! Este es el código completo para la clase ElasticMenu:
paquete import flash.display. *; importar flash.text. *; importar flash.net. *; importar flash.events. *; import flash.utils.Timer; la clase pública ElasticMenu extiende MovieClip var xml: XML; botones var: Array; var tm: temporizador; var maxdist: Número = 50; var linea: Sprite; función pública ElasticMenu () var req = new URLLoader (); req.addEventListener (Event.COMPLETE, xml_loaded); req.load (nueva URLRequest ('menu.xml')); botones = nueva matriz (); tm = nuevo temporizador (40); tm.addEventListener (TimerEvent.TIMER, check_buttons); función privada xml_loaded (e: Event) xml = XML (e.target.data); createButtons (); public function createButtons () var sectw = (stage.stageWidth / (xml… button.length () + 1)); para (var i = 0; i< xml… button.length(); i++) var m = new ElasticButton(); m.x = sectw + (sectw*i); m.y = stage.stageHeight/2; m.init( xml… button[i] ); if( i == 0 ) m.makeStartButton(); if( i == xml… button.length()-1) m.makeEndButton(); addChild( m ); buttons.push( m ); tm.start(); private function check_buttons( e:TimerEvent ) for( var b in buttons ) if( buttons[b].dragging ) buttons[b].x = mouseX; buttons[b].y = mouseY; if( buttons[b].getDistance() > maxdist) botones [b] .reset ();
Y para la clase ElasticButton:
paquete import flash.display. *; importar flash.text. *; importar flash.net. *; importar flash.events. *; importar flash.geom.ColorTransform; importar fl.transitions.Tween; importar fl.transitions.TweenEvent; importar fl.transitions.easing. *; importar fl.motion.Color; la clase pública ElasticButton extiende MovieClip var origin: Object; campo de texto var: TextField; var tf: TextFormat; var arrastrando: Booleano = falso; var bg: Sprite; var url: String; var twx: Tween; var twy: Tween; Acolchado var: Número = 8; color var: uint; var msk: Sprite; función pública ElasticButton () // do nothing función pública init (node) textfield = new TextField (); tf = nuevo TextFormat (); tf.size = 14; tf.font = '_sans'; tf.bold = verdadero; tf.color = 0xffffff; tf.align = TextFormatAlign.CENTER; textfield.defaultTextFormat = tf; textfield.text = nodo ... nombre; textfield.width = 65; textfield.height = 20; textfield.x = - (textfield.width / 2); textfield.y = - (textfield.height / 2); textfield.mouseEnabled = false; addChild (campo de texto); origen = nuevo objeto (); origin.x = this.x; origen.y = este.y; color = nodo ... color; crearBG (); url = nodo ... url; arrastrando = falso; this.buttonMode = true; this.addEventListener (MouseEvent.MOUSE_OVER, mouse_over); this.addEventListener (MouseEvent.CLICK, mouse_click); public function createBG () bg = new GradBackground (); var dbpad = relleno * 2; bg.width = textfield.width + dbpad; bg.height = textfield.height + dbpad; bg.x = - ((textfield.width + dbpad) / 2); bg.y = - ((textfield.height + dbpad) / 2); addChild (bg); var col = nuevo Color (1,1,1,1); col.setTint (color, 0.4); bg.transform.colorTransform = col; setChildIndex (bg, 0); función pública getDistance () return Math.sqrt ((this.x-origin.x) * (this.x-origin.x) + (this.y-origin.y) * (this.y-origin.y )); función pública reset () arrastrando = falso; twx = new Tween (this, 'x', Elastic.easeOut, this.x, origin.x, 0.4, true); twy = new Tween (this, 'y', Elastic.easeOut, this.y, origin.y, 0.4, true); función privada mouse_over (e: MouseEvent) dragging = true; función privada mouse_click (e: MouseEvent) navigationToURL (new URLRequest (this.url)); public function makeStartButton () msk = new Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.moveTo (0, relleno); msk.graphics.curveTo (0, 0, relleno, 0); msk.graphics.lineTo ((relleno * 2) + textfield.width, 0); msk.graphics.lineTo ((padding * 2) + textfield.width, (padding * 2) + textfield.height); msk.graphics.lineTo (0, (relleno * 2) + textfield.height); msk.graphics.lineTo (0, relleno); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (msk); bg.mask = msk; public function makeEndButton () var dbpad = padding * 2; msk = nuevo Sprite (); msk.graphics.beginFill (0x000000,1); msk.graphics.lineTo (textfield.width + padding, 0); msk.graphics.curveTo (textfield.width + dbpad, 0, textfield.width + dbpad, relleno); msk.graphics.lineTo (dbpad + textfield.width, dbpad + textfield.height); msk.graphics.lineTo (0, dbpad + textfield.height); msk.graphics.lineTo (0, relleno); msk.graphics.endFill (); msk.x = bg.x; msk.y = bg.y; addChild (msk); bg.mask = msk;
Ahora, ese fue un tutorial bastante largo! Espero no haber aburrido a nadie. Si tiene alguna idea sobre cómo podríamos mejorar el menú, agréguelos a los comentarios..
!