Reproductor de música en Actionscript 3, usando POO y patrón MVC

Para acabar con la clase Control, nos queda ver los manejadores de evento crearTip() y cerrarTip() que asignábamos a los detectores de rollOver y rollOut de los botones de opción:

// Manejador de los eventos de ROLL_OVER en botones de opción
private function crearTip(e:MouseEvent):void {
      var b:Sprite = e.currentTarget as Sprite;
      switch (b.name) {
          case "botonNoRepeat":
              Tip.crear(_reproductor, "Repeat Off");
          break;
          case "botonRepeatOnce":
              Tip.crear(_reproductor, "Repeat One");
          break;
          case "botonRepeatAll":
              Tip.crear(_reproductor, "Repeat All");
          break;
          case "botonRandomOff":
              Tip.crear(_reproductor, "Random Off");
          break;
          case "botonRandomOn":
              Tip.crear(_reproductor, "Random On");
          break;
          case "barraVolumen":
              Tip.crear(_reproductor, "Volumen");
              b.removeEventListener(MouseEvent.ROLL_OVER, crearTip);
          break;
      }
}

// Manejador de evento ROLL_OUT en botones de opción
private function cerrarTip(e:MouseEvent):void {
      Tip.cerrar();
}

Como se puede observar, crearTip() filtra qué botón ha originado el evento rollOver, y en base a eso, llama a la clase Tip. Esta clase la he creado como clase estática, de manera que no hay que instanciarla, dado que a lo sumo siempre habrá un solo tip, hint, mensaje contextual, o como lo llames. Por lo tanto es llamada directamente, y los métodos son a nivel de clase, no de instancia. El método crear() de Tip lo veremos a continuación, pero comentar que se le pasan como argumentos el propio reproductor, que hará de padre, y el texto del mensaje de ayuda a mostrar.

Vamos ahora a ver esta clase Tip. La he creado con un encapsulamiento total de forma que no necesite de un controlador externo para mostrarse y desaparecer con un retardo de aparición y un tiempo de duración determinados. Ella sola se regula. Solo hay que asignarle un Sprite padre, y un texto al crearla. Ella sola se destruye. Pero también podemos eliminarla nosotros en caso necesario, con cerrar().

Tras echar una ojeada, puedes estar preguntándote, si Tip ya es un Sprite, por qué creo otro Sprite dentro para albergar los gráficos? Bueno, esto ha sido una solución sencilla al hecho de que al tratarse de una clase estática, no puedo usar ciertas palabras clave directamente con ella, como this. Esta palabra clave solo funcion a nivel de instancia, no a nivel de clase. Bueno, sin más dilaciones, este es el código:

package vista {

    import flash.display.Sprite;
    import flash.utils.Timer
    import flash.events.TimerEvent;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormatAlign;
    import flash.display.Graphics;
    import flash.events.MouseEvent;
    import flash.text.Font;
    import flash.filters.DropShadowFilter;

    public class Tip extends Sprite {

        private static var _timer:Timer;
        private static var _padre:Sprite;
        private static var _tip:Sprite;

        private static const TIEMPO_DEMORA = 1000;
        private static const TIEMPO_VISIBLE = 3000; // 3 segundos
        private static const MARGEN = 5;

        public static function crear(padre:Sprite, texto:String):void {
            _padre = padre;
            // Crear contenedor del Tip
            _tip = new Sprite();
            // Asignarle un filtro de sombra para darle relieve y aplicarle un alpha
            var sombra:DropShadowFilter = new DropShadowFilter(2, 45, 0, 6, 2, 2, 1);
            _tip.filters = [sombra];
            _tip.alpha = .8;
            // Creación campo de texto
            var campoTexto:TextField = crearTexto(texto);
            // Creación fondo
            var g:Graphics = _tip.graphics;
            g.beginFill(0xFF9865);
            g.drawRoundRect(0, 0, campoTexto.width + MARGEN, campoTexto.height + MARGEN, 2);
            g.endFill();
            // Situar campo de texto respecto a fondo
            campoTexto.x = campoTexto.y = MARGEN / 2;
            _tip.addChild(campoTexto);
            // Crear timer e iniciarlo. Cuando acabe se mostrará el tip
            _timer = crearTimer(TIEMPO_DEMORA);
        }

        private static function mostrar():void {
            // Colocar Tip inicialmente
            posicionar();
            // Hacer que el Tip se mueva respecto del ratón
            _padre.addEventListener(MouseEvent.MOUSE_MOVE, recolocar);
            // Hacer visible el tip
            _padre.addChild(_tip);
            // Crear el temporizador de visibilidad
            _timer = crearTimer(TIEMPO_VISIBLE);
        }

        private static function crearTexto(texto:String):TextField {
            var campoTexto:TextField = new TextField();
            var formato:TextFormat = new TextFormat();
            var fuente:Font = new CenturyGothicRegular(); // Importar fuente incrustada en biblioteca
            campoTexto.autoSize = TextFieldAutoSize.CENTER;
            campoTexto.multiline = true;
            campoTexto.wordWrap = true;
            campoTexto.embedFonts = true;
            formato.color = 0x000000;
            formato.font = fuente.fontName;
            formato.size = 10;
            formato.letterSpacing = .5;
            formato.align = TextFormatAlign.CENTER;
            campoTexto.defaultTextFormat = formato;
            campoTexto.text = texto;
            return campoTexto;
        }

        private static function recolocar(e:MouseEvent):void {
            posicionar();
        }

        private static function posicionar():void {
            _tip.x = _padre.mouseX + 10;
            _tip.y = _padre.mouseY - _tip.height - 10;
        }

        private static function crearTimer(tiempoTotal:int):Timer {
            var timer:Timer = new Timer(tiempoTotal, 1);
            timer.addEventListener(TimerEvent.TIMER, finTimer);
            timer.start();
            return timer;
        }

        private static function finTimer(e:TimerEvent):void {
            _timer.removeEventListener(TimerEvent.TIMER, finTimer);
            if (!_padre.contains(_tip)) {
                mostrar();
            } else {
                cerrar();
            }
        }

        public static function cerrar():void {
            if (_timer != null) {
                _timer.removeEventListener(TimerEvent.TIMER, finTimer);
                _timer = null;
            }
            if (_tip != null && _padre.contains(_tip)) {
                _padre.removeEventListener(MouseEvent.MOUSE_MOVE, recolocar);
                _padre.removeChild(_tip);
                _tip = null;
            }
        }
    }
}

El constructor de esta clase crea un Sprite contenedor para albergar los elementos gráficos, le añade un filtro de sombra y algo de transparencia alfa, posteriormente crea el campo de texto con formato, usando la fuente incrustada, gracias al método crearTexto(). Seguidamente se crea el recuadro de fondo con la clase Graphics, se sitúa el campo de texto con respecto al fondo, y se añade el campo de texto a la display list del Sprite contenedor. Para acabar en el constructor, se crea el temporizador de tiempo de demora o retardo hasta mostrar el mensaje, llamando al método crearTimer(). Se le asigna un detector para que pasado el tiempo de demora, se ejecute finTimer(). Este método filtra si el tip se está mostrando ya o no. En este caso aún no se está mostrando, así que llama al método mostrar(), el cual posiciona y muestra en pantalla el tip a una distancia determinada del puntero del ratón, y le asigna un detector de mouseMove al padre para que detecte cada vez que se mueva el ratón sobre él, de forma que se recolocará el tip siguiendo al ratón. Finalmente se recrea el temporizador, dándole un tiempo de duración del mensaje. Cuando este tiempo acabe, se ejecutará de nuevo finTimer(), pero esta vez al estar mostrándose el tip, se llamará a cerrar(), que eliminará el temporizador y el gráfico del tip.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>