lunes, 2 de febrero de 2009

Video tutorial Creacion de un componente Flex


En este tutorial voy a explicar los principios básicos a seguir para la creación de un componete flex. Para lograr esto vamos a crear un componente que cotenga un rectangulo que se mueva. Cada vez que este componente sea agregado a una aplicacion flex, entonces la aplciación tendrá un cuadrado que se mueva hacia la derecha. Por mas inutil que resulte este componente, me parece perfecto ejemplo didáctico. De todas maneras próximamente prometo crear componentes mas utiles y explicar como los hice.

Para empezar el tutorial debemos entender los conceptos básicos que estan presentes en todos los componentes flex, es decir, en todas las clases de flex que heredan de la clase UIComponent (que es el componente mas básico).

Parte I

Parte II


La clase UIComponente propone 5 métodos fundamentales a utilizar:

  1. contructor: Este metodo se llama de primero en todos los componentes flex, lleva el mismo nombre que la clase que se esta creando. Permite inicializar variables entre otras coas.
  2. createChildren: Este metodo se utiliza para agregar hijos al componente, todos los componentes tienen una lista de hijos dentro de si, todos estos hijos son actualizados por otros métodos como updateDisplayList, para que un objeto pueda ser hijo de un componente debe heredar de la clase DisplayObject. Este metodo solo se ejecuta una vez al inicializarse el componente. Los hijos que se quieran agregar después deben agregarse en otros segmentos de código.
  3. commitProperties: Este metodo se invoca para definir o actualizar las propiedades del componente. Se puede ejecutar varias veces, y siempre se ejecuta la rimera vez justo despues del metodo createChildren.
  4. measure: Este metodo se utiliza para definir el tamaño del componente, cada vez que flex no sabe que tamaño tiene el componente entra en este método. Es importante saber que si se define un tamaño explicito (width y height) al componente entonces flex no entrará mas en este método.
  5. updateDisplayList: Este método se encarga de pintar el componente, en este lugar se ejecutan todas las sentencias de coódigo que tengan que ver con la visualizacion del componente. Tambien se ejecuta muchas veces.
Cuando un componente es creado por primera vez por flex todos estos metodos se ejecutan en el siguiente orden:



Es importante saber que estos tres últimos métodos mencionados no se pueden invocar directamente, si queremos llamarlos debemos utilizar unas funciones pensadas para eso:

La razón de no llamar a estos métodos directamente es porque el framewor de flex debe llamarlos cuando lo considere pertinente, es decir, con los métodos invalidateProperties, invalidateSize e invalidateDisplayList del LayoutManager nosotros le decimos a flesx que porfavor los llame, a partir de ese momento flex esperará el momento adecuado para llamarlos. Esto debemos tenerlo siempre en cuanta para que no valla a darnos problemas en un futuro.

Creando nuestro componente.

Recuerden que el componente que vamos a crear se encargará de dibujar un rectangulo e irlo moviendo hacia la derecha. Para crear el componente vamos a agregar una nueva actionScript Class que llamaremos MyFirstComponent.as donde colocaremos el siguiente código:
Código MyFirstComponent.as

package com.view
{
import flash.events.TimerEvent;
import flash.utils.Timer;

import mx.core.UIComponent;
import mx.skins.ProgrammaticSkin;


public class MyFirstComponent extends UIComponent
{
/*
Defino las variables que voy a utilizar en este componente.
*/
private var bloque : ProgrammaticSkin;
private var _timer : Timer = new Timer(50);
private var procesarBloque : Boolean = false;

public function MyFirstComponent()
{
super();
trace("constructor");
/*
Empiezo el timer y defino un handler llamado pintar para el evento
TimerEvent.TIMER que es disparado por el timer cada 50 miliseg.

*/
_timer.addEventListener(TimerEvent.TIMER,pintar);
_timer.start();
}

override protected function createChildren() : void
{
super.createChildren();
/*
Creo un ProgrammaticSkin y lo agrego a la lista de hijos del
componente.
*/
bloque = new ProgrammaticSkin();
this.addChild(bloque);

trace("createChildren");
}

/*
Utilizamos este metodo para cambiar el tamaño de nuestro componente
*/
override protected function measure() : void
{
super.measure();
trace("measure");

measuredWidth += 30;
measuredHeight += 30;

}


override protected function commitProperties() : void
{
super.commitProperties();
trace("commitProperties");

/*
Debemos asegurarnos de que "bloque" este creado.
*/
if(bloque)
{
//Solo queremos aumentar la coordenada x de "bloque" si es menor a 100.
if(bloque.x<100) procesarBloque = true;
else procesarBloque = false;

/*
Esta condicional nos permite restringir los bloques que deseamos que sean procesados
esto se puede usar para mejorar el rendimiento del componente ya que de esta manera
podemos controlar la ejecucion de las porciones de codigo, no se debe ejecutar la
porcion que no sea necesaria.
*/
if(procesarBloque)
{
bloque.x++;
}
}

}


override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);

trace("updateDisplayList");

/*
En este punto pintamos nuestro bloque con el el ancho y alto de 200.
es importante dear de pintar a "bloque si no han ocurrido modificaciones de sus propiedads,
para eso usamos la bandera "procesarBloque" que tambien la utilizamos en el commmitproperties
*/
if(procesarBloque)
{
//bloque.graphics.clear();
bloque.graphics.lineStyle(1,0x000000,1);
bloque.graphics.beginFill(Math.random() * 20000000, 1);
bloque.graphics.moveTo(unscaledWidth,unscaledHeight);
bloque.graphics.lineTo(unscaledWidth,0);
bloque.graphics.lineTo(0,0);
bloque.graphics.lineTo(0,unscaledHeight);
}


}

/*
Esta funcion se llama cada 50 milisegundos.
*/
public function pintar(e : TimerEvent) : void
{
//Le digo a flex que cuando considere pertinente puede hacer
//un llamado a la funcion "commitProperties".
this.invalidateProperties();
this.invalidateDisplayList();
this.invalidateSize();


}
}
}


Las variable bloque será donde pintaremos todo nuestro cuadrado, un ProgrammaticSkin es una clase muy liviana que permite utilizar shapes sobre ellas, es decir, pintar lineas y rellenarlas.

La variable _timer se encargará de hacer una llamada a las funciones invalidateProperties, invalidateSize e invalidateDisplayList cada 50 milisegundos para que el cuadrado pintado se refresque visualmente y para que se le modifique su tamaño y propiedades.

La variable procesarBloque se definió para restringir los bloques de codigo que seran ejecutados cada vez que se llame al método commitproperties y updateDisplayList (ya que como estos métodos los vamos a llamar frecuentemente, es mejor que no se ejecute todo el codigo que ellos contienen constantemente.).

En el método create children debemos instanciar y agregar el ProgrammaticSkin que definimos ("bloque") al componente (para que pueda ser visualizado).

override protected function createChildren() : void
{
super.createChildren();
/*
Creo un ProgrammaticSkin y lo agrego a la lista de hijos del
componente.
*/
bloque = new ProgrammaticSkin();
this.addChild(bloque);

trace("createChildren");
}

En el método commitProperties se encargará de aumentar la propiedad "x" de la variable "bloque" para que el cuadradro que esta represente se mueva hacia la derecha.

override protected function commitProperties() : void
{
super.commitProperties();
trace("commitProperties");

/*
Debemos asegurarnos de que "bloque" este creado.
*/
if(bloque)
{
//Solo queremos aumentar la coordenada x de "bloque" si es menor a 100.
if(bloque.x<100) procesarBloque = true;
else procesarBloque = false;

/*
Esta condicional nos permite restringir los bloques que deseamos que sean procesados
esto se puede usar para mejorar el rendimiento del componente ya que de esta manera
podemos controlar la ejecucion de las porciones de codigo, no se debe ejecutar la
porcion que no sea necesaria.
*/
if(procesarBloque)
{
bloque.x++;
}
}

}

El metodo updateDisplayList se encargara de volver a pintar el cuadrado ahora que esta un podo mas a la derecha (porque commitProperties lo movio hacia la derecha.).

override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);

trace("updateDisplayList");

/*
En este punto pintamos nuestro bloque con el el ancho y alto de 200.
es importante dear de pintar a "bloque si no han ocurrido modificaciones de sus propiedads,para eso usamos la bandera "procesarBloque" que tambien la utilizamos en el commmitproperties
*/
if(procesarBloque)
{
//bloque.graphics.clear();
bloque.graphics.lineStyle(1,0x000000,1);
bloque.graphics.beginFill(Math.random() * 20000000, 1);
bloque.graphics.moveTo(unscaledWidth,unscaledHeight);
bloque.graphics.lineTo(unscaledWidth,0);
bloque.graphics.lineTo(0,0);
bloque.graphics.lineTo(0,unscaledHeight);
}

}

El metodo measure le da el tamaño inicial al componente.

override protected function measure() : void
{
super.measure();
trace("measure");

measuredWidth += 30;
measuredHeight += 30;

}

Luego de crear todos estos metodos debemos ejecutar la aplicacion en modo debugger (para que veamos lo que va arrojando la funcion trace).

Espero que les haya servido este tutorial, cualquier duda que tengan pueden escribirme al mail aalejo@gmail.com o dejar un comentario en la parte de abajo de esta página.

Ejemplo



1 comentario:

  1. Es un muy didactico tu tutorial, muchas gracias Alejandro!

    ResponderEliminar