Flash - Trabalhando com objetos na biblioteca

Há algum tempo atrás eu escrevi um pequeno post, que mostrava como anexar itens da biblioteca ao palco no AS3, uma vez que o attachMovie do AS2 foi pras cucuias.
Acontece que a maioria que tenta migrar do AS2 para o AS3 não percebe que existe uma sutil mudança na lógica de como as coisas funcionam.

Atenção: Todos os exemplos aqui apresentados se encontram para download, portanto não vou entrar em detalhes sobre a criação dos elementos, e sim me focar no que realmente interessa: AS.

No AS2 para anexarmos um item da biblioteca ao palco, era muito simples:


// attachMovie(name, new name, depth);
var item:MovieClip = attachMovie(“Item”, “NewItem”, 10);

Não que no AS3 tenha ficado difícil, apenas mudou:


var item:Item = new Item();

Isso porque a coisa mudou, para alguns mudou um pouco e para outros mudou absurdamente. O que afeta a maioria na verdade é que agora OOP é realmente OOP, não existe essa coisa de “meio” orientado. Então, um objeto é realmente um objeto, e deve ter uma classe responsável por ele.

O que o Flash faz hoje é, ao invés de usar um linkage como antigamente, utiliza uma classe. Se a classe não existe, ela é criada internamente, isso porque o objeto tem que ter uma classe. Sem classe, sem objeto, sacou?

Dessa forma, algumas pessoas podem criar uma certa confusão na cabeça, se não tiverem uma lógica já orientada, mas não se preocupe que isso é moleza de consertar.
Vou criar aqui uma pequena galeria de imagens, simples, realmente simples, focando apenas no nosso problema que é o tal do “attachMovie” no AS3.

Esta será a nossa estrutura de XML, indicando as imagens de nossa galeria:


<?xml version="1.0" encoding="utf-8"?>
<images>
<image path="thumb1.jpg" subtitle="Image 1" />
<image path="thumb2.jpg" subtitle="Image 2" />
<image path="thumb3.jpg" subtitle="Image 3" />
<image path="thumb4.jpg" subtitle="Image 4" />
<image path="thumb5.jpg" subtitle="Image 5" />
</images>

No AS2, para carregar o XML e criar os thumbs faríamos algo assim:


// Caminho para o arquivo XML.
var path:String = "images.xml";

// Posições iniciais.
var xIni:Number = 0;
var yIni:Number = 0;

/**
* Carrega o documento XML.
*
* @param path Caminho para o arquivo XML a ser carregado.
* @return void
*/
function loadXML(path:String):Void
{
// Objeto XML.
var xml:XML = new XML();

// Ignora os espaços em branco do documento.
xml.ignoreWhite = true;

// Handler disparado quando o documento é carregado.
xml.onLoad = this.loadXMLHandler;

// Carregando documento.
xml.load(path);
}

/**
* Handler disparado quando o documento XML é carregado.
*
* @param success Indica se o documento foi carregado.
* @return void
*/
function loadXMLHandler(success:Boolean):Void
{
// Raiz do XML.
var node:XMLNode = this.firstChild;

// Exibindo thumbs.
showThumbs(node);
}

/**
* Cria e exibe os thumbs no palco.
*
* @param node Nó XML contendo as imagens.
* @return void
*/
function showThumbs(node:XMLNode):Void
{
// Para cada imagem existente.
for (var i:Number = 0; i < node.childNodes.length; i++)
{
// Caminho da imagem.
var path:String = node.childNodes[i].attributes.path;

// Subtitle da imagem.
var subtitle:String = node.childNodes[i].attributes.subtitle;

// Modelo de thumb que está na biblioteca.
var thumb:MovieClip = attachMovie("Thumb", "thumb" + i, this.getNextHighestDepth());

// Objeto MCL, responsável por carregar a imagem.
var loader:MovieClipLoader = new MovieClipLoader();

// Carregando e definindo imagem do thumb.
loader.loadClip(path, thumb.image);

// Definindo subtitulo do thumb.
thumb.subtitleText.text = subtitle;

// PosX.
thumb._x = this.xIni += ((i % 2) == 0) ? 0 : thumb._width + 10;

// PosY.
thumb._y = this.yIni;

// Truque barato para quem tem preguiça de
// setar uma variável para as colunas.
if ((i % 2) == 1)
{
this.xIni = 0;
this.yIni += thumb._height + 10;
}
}
}

// Iniciando a coisa toda.
this.loadXML(path);

Aviso aos navegantes: O código acima só vai funcionar se você definir um linkage “Thumb” para o objeto na Biblioteca. Para definir, vá na biblioteca, clique com o botão direito sobre o objeto e clique em “Linkage”. Na tela que abrir, no campo Identifier coloque o nome que deseja, no caso deste exemplo, “Thumb”.

Fique atento para esta parte:


// Modelo de thumb que está na biblioteca.
var thumb:MovieClip = attachMovie("Thumb", "thumb" + i, this.getNextHighestDepth());

Aqui, nós anexamos o nosso objeto MovieClip da biblioteca ao palco. Vamos ver como isso é feito no AS3. A primeira mudança que vemos, é que não usamos mais um valor no campo Identifier como anteriormente, e sim, definimos um Class Name.


import flash.net.URLLoader;
import flash.net.URLRequest;

// Caminho para o arquivo XML.
var path:String = "images.xml";

// Lista de imagens.
var _list:XMLList = null;

// Posições iniciais.
var xIni:int = 0;
var yIni:int = 0;

/**
* Carrega o documento XML.
*
* @param path Caminho para o arquivo XML a ser carregado.
* @return void
*/
function loadXML(path:String):void
{
// URL que contém o XML.
var urlrequest:URLRequest = new URLRequest(path);

// Carrega o conteúdo da URL especificada.
var urlloader:URLLoader = new URLLoader(urlrequest);

// Evento COMPLETE disparado quando o XML é carregado.
urlloader.addEventListener(Event.COMPLETE, this.loadXMLHandler);
}

/**
* Handler disparado quando o documento XML é carregado.
*
* @param success Indica se o documento foi carregado.
* @return void
*/
function loadXMLHandler(evt:Event):void
{
// Objeto XML, contendo o XML carregado.
var xml:XML = new XML(evt.currentTarget.data);

// Lista de nós contendo as imagens.
this._list = xml.image;

// Exibindo thumbs.
this.showThumbs();
}

/**
* Cria e exibe os thumbs no palco.
*
* @return void
*/
function showThumbs():void
{
// Para cada imagem existente.
for (var i:int = 0; i < this._list.length(); i++)
{
// Caminho da imagem.
var path:String = this._list[i].@path;

// Subtitle da imagem.
var subtitle:String = this._list[i].@subtitle;

// Objeto Thumb que está na biblioteca.
var thumb:Thumb = new Thumb();

// Objeto Loader, responsável por carregar a imagem.
var loader:Loader = new Loader();

// URL do arquivo de imagem.
var url:URLRequest = new URLRequest(path);

// Carregando imagem.
loader.load(url);

// Adicionando imagem carregada ao thumb.
thumb.image.addChild(loader);

// Definindo subtitle do thumb.
thumb.subtitleText.text = subtitle;

// PosX.
thumb.x = this.xIni += ((i % 2) == 0) ? 0 : thumb.width + 10;

// PosY.
thumb.y = this.yIni;

// Adicionando thumb ao palco.
this.addChild(thumb);

// Truque barato para quem tem preguiça de
// setar uma variável para as colunas.
if ((i % 2) == 1)
{
this.xIni = 0;
this.yIni += thumb.height + 10;
}
}
}

// Iniciando a coisa toda.
this.loadXML(path);

A diferença está toda no modo em como anexamos nosso objeto. Uma vez que não usamos mais um “identifier” e sim um nome de classe, o Flash cria a classe especificada de forma interna, e passa a tratar o nosso símbolo como sendo um objeto daquela classe, no caso, “Thumb”.


// Objeto Thumb que está na biblioteca.
var thumb:Thumb = new Thumb();

Ao definirmos uma classe para o nosso objeto da biblioteca, o Flash procura por ela. Se achar, usa a classe existente, senão, cria uma classe internamente, apenas como referência.

Então, se quisermos criar uma classe para o nosso objeto…


import app.display.Thumb;

import flash.net.URLLoader;
import flash.net.URLRequest;

var path:String = "images.xml";
var _list:XMLList = null;
var xIni:int = 0;
var yIni:int = 0;

/**
* Carrega o documento XML.
*
* @param path Caminho para o arquivo XML a ser carregado.
* @return void
*/
function loadXML(path:String):void
{
// URL que contém o XML.
var urlrequest:URLRequest = new URLRequest(path);

// Carrega o conteúdo da URL especificada.
var urlloader:URLLoader = new URLLoader(urlrequest);

// Evento COMPLETE disparado quando o XML é carregado.
urlloader.addEventListener(Event.COMPLETE, this.loadXMLHandler);
}

/**
* Handler disparado quando o documento XML é carregado.
*
* @param success Indica se o documento foi carregado.
* @return void
*/
function loadXMLHandler(evt:Event):void
{
// Objeto XML, contendo o XML carregado.
var xml:XML = new XML(evt.currentTarget.data);

// Lista de nós contendo as imagens.
this._list = xml.image;

// Exibindo thumbs.
this.showThumbs();
}

/**
* Cria e exibe os thumbs no palco.
*
* @return void
*/
function showThumbs():void
{
// Para cada imagem existente.
for (var i:int = 0; i < this._list.length(); i++)
{
// Caminho da imagem.
var path:String = this._list[i].@path;

// Subtitle da imagem.
var subtitle:String = this._list[i].@subtitle;

// Objeto Thumb que está na biblioteca.
var thumb:Thumb = new Thumb();

// Carregando imagem no thumb.
thumb.loadImage(path);

// Definindo subtitle no thumb.
thumb.subtitle = subtitle;

// Pos X.
thumb.x = this.xIni += ((i % 2) == 0) ? 0 : thumb.width + 10;

// Pos Y.
thumb.y = this.yIni;

// Adicionando thumb ao palco.
this.addChild(thumb);

// Truque barato para quem tem preguiça de
// setar uma variável para as colunas.
if ((i % 2) == 1)
{
this.xIni = 0;
this.yIni += thumb.height + 10;
}
}
}

// Iniciando a coisa toda.
this.loadXML(path);

O primeiro passo aqui foi remover tudo o que, de certa forma, pertence ao Thumb. Se você comparar o código atual com o anterior, irá perceber que toda a parte de carregamento da imagem do Thumb não se encontra mais aí, pois vamos implementá-la no próprio objeto.

Thumb.as


package app.display
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.events.Event;
import flash.net.URLRequest;
import flash.text.TextField;

public class Thumb extends MovieClip
{

// Comentei as duas propriedades, somente para lembrar quais
// são os elementos que temos dentro do nosso Thumb.
// O Flash CS3 alerta conflito interno se você declarar elementos
// de mesmo nome na classe e no movieclip (Thumb), no CS4
// esse erro não ocorre.

//public var image:MovieClip;
//public var subtitleText:TextField;

/**
* Construtor
*/
public function Thumb()
{

}

/**
* Define o valor de subtitleText.
*
* @param value Texto do subtitle.
* @return void
*/
public function set subtitle(value:String):void
{
this.subtitleText.text = value;
}

/**
* Carrega a imagem do thumbnail.
*
* @param path Caminho da imagem.
* @return void
*/
public function loadImage(path:String):void
{
var loader:Loader = new Loader();
var url:URLRequest = new URLRequest(path);

loader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.loadHandler);
loader.load(url);
}

/**
* Handler do evento COMPLETE do objeto loader.
*
* @param evt Event.COMPLETE
*/
private function loadHandler(evt:Event):void
{
var contentLoaded:DisplayObject = evt.currentTarget.loader as DisplayObject;
this.image.addChild(contentLoaded);
}

}

}

Nossa classe deve herdar obrigatoriamente a classe MovieClip, pois nosso objeto é derivado desta classe.

O que mudou? Bom, separamos toda a lógica do Thumb em sua classe, fazendo com que seu código não fique misturado com o código de outras partes da aplicação.

Antes tínhamos:


// Objeto Thumb que está na biblioteca.
var thumb:Thumb = new Thumb();

// Objeto Loader, responsável por carregar a imagem.
var loader:Loader = new Loader();

// URL do arquivo de imagem.
var url:URLRequest = new URLRequest(path);

// Carregando imagem.
loader.load(url);

// Adicionando imagem carregada ao thumb.
thumb.image.addChild(loader);

// Definindo subtitle do thumb.
thumb.subtitleText.text = subtitle;

Agora…


// Objeto Thumb que está na biblioteca.
var thumb:Thumb = new Thumb();

// Carregando imagem no thumb.
thumb.loadImage(path);

// Definindo subtitle no thumb.
thumb.subtitle = subtitle;

Isso sem contar os métodos que estavam espalhados por aí. :)
Como você pode ver, é tudo uma questão de lógica. Abrir mão de métodos como attachMovie foi algo necessário para que pudéssemos aplicar realmente a OOP em nossos códigos, de forma correta, organizada e lógica.

Mas… se temos uma galeria, não deveríamos separar o código dela também? Digo, temos os Thumbs e temos a Galeria não? Não seria possível eu ter uma classe para controlar minha galeria também?

Sim, é possível sim, basta criarmos um MovieClip e aplicarmos uma classe a ele.

Gallery.as


package app.display
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;

public class Gallery extends MovieClip
{

private var _list:XMLList = null;
private var _thumbs:Array = new Array();
private var _xmlPath:String = "";
private var xIni:int = 0;
private var yIni:int = 0;

/**
* Construtor
*/
public function Gallery()
{

}

/**
* Define o caminho para o XML da galeria e inicia o processo.
*
* @param value Caminho para o arquivo XML.
* @return void
*/
public function set xmlPath(value:String):void
{
this._xmlPath = value;
this.loadXML(value);
}

/**
* Carrega o arquivo XML especificado em path.
*
* @param path Caminho do arquivo XML.
* @return void
*/
private function loadXML(path:String):void
{
// URL que contŽm o XML.
var urlrequest:URLRequest = new URLRequest(path);

// Carrega o conteœdo da URL especificada.
var urlloader:URLLoader = new URLLoader(urlrequest);

// Evento COMPLETE disparado quando o XML Ž carregado.
urlloader.addEventListener(Event.COMPLETE, this.loadXMLHandler);
}

/**
* Handler disparado quando o documento XML Ž carregado.
*
* @param success Indica se o documento foi carregado.
* @return void
*/
private function loadXMLHandler(evt:Event):void
{
// Objeto XML, contendo o XML carregado.
var xml:XML = new XML(evt.currentTarget.data);

// Lista de n—s contendo as imagens.
this._list = xml.image;

// Exibindo thumbs.
this.showThumbs();
}

/**
* Exibe e cria os thumbs.
*
* @return void
*/
private function showThumbs():void
{
// Para cada imagem existente.
for (var i:int = 0; i < this._list.length(); i++)
{
// Caminho da imagem.
var path:String = this._list[i].@path;

// Subtitle da imagem.
var subtitle:String = this._list[i].@subtitle;

// Objeto Thumb que est‡ na biblioteca.
var thumb:Thumb = new Thumb();

// Carregando imagem no thumb.
thumb.loadImage(path);

// Definindo subtitle no thumb.
thumb.subtitle = subtitle;

// Pos X.
thumb.x = this.xIni += ((i % 2) == 0) ? 0 : thumb.width + 10;

// Pos Y.
thumb.y = this.yIni;

// Adicionando thumb ao array.
this._thumbs.push(thumb);

// Adicionando thumb ao palco.
this.addChild(thumb);

// setar uma vari‡vel para as colunas.
if ((i % 2) == 1)
{
this.xIni = 0;
this.yIni += thumb.height + 10;
}
}
}

}

}

O único código que necessitamos em nosso FLA é este:


import app.display.Gallery;

var g:Gallery = this.gallery;
g.xmlPath = "images.xml";

A maior vantagem em tudo isto é a organização que temos em nosso código, nunca mais você terá aquele problema de não achar o código em meio a tantos keyframes e símbolos. :)

O objetivo deste foi mostrar um comparativo da forma como trabalhávamos antigamente no AS2 com símbolos vindos da biblioteca, e como fazemos hoje no AS3. Os exemplos estão todos em um arquivo para download, para que você possa ver de perto como tudo isto foi feito, alterar e efetuar os testes da maneira que te der na telha.

Abraço pessoal, se tiverem dúvidas ou sugestões, basta deixar um comentário.

Faça download dos exemplos.

This entry was posted on Sunday, August 31st, 2008 at 18:05 and is filed under ActionScript 3.0, Flash. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply