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

Ahora vamos a pasar a ver la clase BarraTiempo, que también contendrá código adicional. Al estar contenida en la instancia de la clase Reproductor. Su método constructor es ejecutado automáticamente cuando se añade el reproductor al escenario:

package vista {

	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.events.Event;

	public class BarraTiempo extends Sprite {

		private var _puntero:Sprite;
		private var _barraCarga:Sprite;
		private var _punteroArrastrando:Boolean = false;

		public const PUNTERO_SOLTADO = "punteroSoltado";

		public function BarraTiempo() {
			_barraCarga = this.getChildByName("barraCarga") as Sprite;
			_puntero = this.getChildByName("puntero") as Sprite;
			_puntero.addEventListener(MouseEvent.MOUSE_DOWN, moverPuntero);
			_puntero.addEventListener(MouseEvent.MOUSE_OUT, soltarPuntero);
			_puntero.addEventListener(MouseEvent.MOUSE_UP, soltarPuntero);
			_puntero.buttonMode = true;
			reset();
		}

		private function moverPuntero(e:MouseEvent):void {
			var rect:Rectangle = new Rectangle(_barraCarga.x, 0, _barraCarga.width - _puntero.width, 0);
			_puntero.startDrag(false, rect);
			_punteroArrastrando = true;
		}

		private function soltarPuntero(e:MouseEvent):void {
			if (_punteroArrastrando) {
				_puntero.stopDrag();
				_punteroArrastrando = false;
				dispatchEvent(new Event(PUNTERO_SOLTADO));
			}
		}

		public function reset():void {
			_puntero.x = 0;
		}

		public function actualizar(posActual:int, posTotal:int):void {
			if (!_punteroArrastrando) {
				// Se obtiene una fracción relativa partiendo del tiempo actual y el total (ambos en milisegundos)
				var posRel:Number = posActual / posTotal;
				// Aplicar esa fracción al ancho total de la barra para aplicar la posición relativa del puntero
				// respecto de la barra. Al ancho total se le resta antes el ancho del puntero para que no tenga
				// en cuenta ese pequeño ancho.
				_puntero.x = (this.width - _puntero.width) * posRel;
			}
		}

		public function actualizarBuffer(escala:Number):void {
			_barraCarga.scaleX = escala;
		}

		public function get xPuntero():Number {
			return _puntero.x;
		}
	}
}

El constructor de la barra de tiempo guarda en propiedades de clase las referencias a la barra de carga y del puntero, y después asigna detectores de ratón al puntero y lo resetea, o sea, lo coloca al principio de esta. Si hiciéramos clic sobre el puntero, lo podríamos arrastrar a lo largo de la barra de carga, y soltarlo. Al hacer esto último, se dispara el evento punteroSoltado mencionado anteriormente, de forma que el reproductor tendrá constancia de ello y actuará en consecuencia. Lo veremos más adelante. El método actualizar() es llamado desde fuera y cada vez que es llamado va colocando el puntero en una posición determinada de la barra dependiendo del tiempo de reproducción actual de la canción. El método actualizarBuffer() actualiza la barra de carga en base a una escala. Es llamado cada vez que se reciben datos nuevos de la carga de la canción. Por último, tenemos un getter de la posición x del puntero.

Vamos a continuar con la clase Control, que habíamos dejado tras ver su constructor, que cargaba los datos externos. Después del constructor tenemos lo siguiente:

private function onDatosXML(e:Event):void {
    var xml:XML = new XML(e.target.data);
    crearPlaylist(xml);
}

private function crearPlaylist(datos:*):void {
    _playlist = new Playlist(datos);
    // Una vez creada la playlist, mostrarla en el List del reproductor,
    mostrarLista();
    // Una vez la lista completada, se puede inicializar reproductor para su reproducción
    _reproductor.inicializar(_playlist);
    // y llamar al método de control del reproductor
    controlReproductor();
}

El método onDatosXML es el manejador del detector de carga de datos XML completada. Una vez tenemos los datos, podemos hacer como en el caso de los datos obtenidos a través de un SharedObject, o sea, proceder a la creación de la Playlist, mostrarla, inicializar el reproductor una vez mostrada, y controlar desde Control todos los botones del reproductor. Cada uno de estos métodos se va a ir viendo. Pero primero de todo, vamos a la clase Playlist, pertenceciente al Modelo de datos. Al crear la instancia le pasamos como parámetro un objeto XML o un Array, por eso hemos de dejar la declaración del tipo de datos con un asterisco.

package modelo {

	import modelo.Cancion;
	import flash.net.SharedObject;

	public class Playlist {

		protected var _lista:Array;
		protected var _shared:SharedObject;

		public function Playlist(lista:*) {

			_lista = new Array();

			_shared = SharedObject.getLocal("playlist");

			if (lista is XML) {
				// No hay lista, se crea una nueva a partir de los datos xml por defecto
				for (var i:uint = 0; i < lista.cancion.length(); i++) {
					var cancion:Cancion = new Cancion(lista.cancion[i]);
					_lista.push(cancion);
				}
				_shared.data.lista = _lista; // Almacenar localmente dicha lista para próximos usos
				_shared.flush();
			} else if (lista is Array) {
				// Hay lista
				_lista = lista;
			}

		}

		public function get lista():Array {
			return _lista;
		}

		public function addToList(cancion:Cancion):void {
			_lista.push(cancion);
			// Actualizar datos en almacen local
			_shared.data.lista = _lista;
			_shared.flush();
		}

	}
}

Esta clase lo que hace es recibir, bien datos XML, bien un Array ya formateado como necesitamos (y que teníamos almacenado en un objeto compartido). Si se trata de datos XML, los “parseamos” y creamos el Array _lista tal y como lo queremos: una lista de instancias de la clase Cancion. Dicha lista ha de estar disponible para la clase que la solicite gracias al método getter lista()

Paramos a la clase Cancion, también muy sencilla, que hace de modelo de datos para almacenar cada instancia de una sola canción:

package modelo {

	public class Cancion {

		private var _id:uint;
		private var _nombre:String;
		private var _artista:String;
		private var _ruta:String;

		public function Cancion(cancion:XML) {
			_id = cancion.id;
			_nombre = cancion.nombre;
			_artista = cancion.artista;
			_ruta = cancion.ruta;
		}

		public function get id():uint {
			return _id
		}

		public function get nombre():String {
			return _nombre
		}

		public function get artista():String {
			return _artista
		}

		public function get ruta():String {
			return _ruta
		}
	}
}

Esta clase se limita a almacenar los datos de una canción dada, y tiene que poder proporcionarlos cuando se le solicite.

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>