Olá amigos e amigas! Para quem não me conhece, sou um dos moderadores do Fórum de Flash do iMasters e é com imenso prazer que publico meu primeiro artigo aqui no portal. Vamos lá!
Esse artigo abranje duas áreas distintas que se interligam pelo XML. A primeira delas será entre o Flash e o XML, a montagem final dos tickers. Depois explicarei como mudar esse XML dinamicamente através do cadastro em BD.
Veja nesse link uma prévia de como ficará o nosso sistema.
Segue agora a primeira parte:
Relacionando o Flash com XML
Esse artigo é de nível intermediário, pois alguns conceitos de Flash e de programação são exigidos.
Vamos ver agora como ler os dados do xml e transformar as informações em aplicações práticas.
1. Criando o arquivo xml antes de tudo.
CODE
<?xml version="1.0" encoding="utf-8"?>
<tickers>
<ticker>
<titulo>Uma vista</titulo>
<area>Montanhas</area>
<texto>Table Mountain and Cape Town</texto>
<foto>foto1.jpg</foto>
<link>http://www.ponha-o-link-que-quiser.com.br</link>
</ticker>
<ticker>
<titulo>Manobra Radical</titulo>
<area>Esportes</area>
<texto>Inline Skater on Vertical Rise of Ramp</texto>
<foto>foto2.jpg</foto>
<link>http://www.ponha-o-link-que-quiser.com.br</link>
</ticker>
<ticker>
<titulo>Com grande angular</titulo>
<area>Cidade</area>
<texto>View of Ibiza Town</texto>
<foto>foto3.jpg</foto>
<link>http://www.ponha-o-link-que-quiser.com.br</link>
</ticker>
</tickers>
Providenciei um .zip com o .xml e as fotos para ficar mais fácil.
Reparem na estrutura do arquivo. Ele tem uma tag que cobre todas as outras e tags menores (<ticker>), cada uma com os dados de uma notícia, foto, ou qualquer coisa para que você utilize o sistema.
2. Agora nós vamos preparar a interface no Flash. Abra um novo documento e adicione:
- Um botão com setinhas para a esquerda chamado “ant_btn”.
- Um botão com setinhas para a direita chamado “prox_btn”. Pode ser o outro botão espelhado. Arraste uma cópia dele e vá em Modify > Transform > Flip Horizontal. Recomendo isso porque economiza bytes.
- Um mc grandão que ocupará a área das fotos chamado “area_mc”.
Misture bem até que se tenha uma massa homogênea e reserve. Dê uma olhada:
2.1. Crie um quadradinho, que servirá de botão para o menu, e transforme-o num mc de nome de instância “menu”. Dentro dele crie uma nova layer e coloque um botão invisível (com conteúdo apenas do frame HIT) do tamanho do quadradinho e chame-o de “botao”. Numa layer abaixo coloque um Dynamic Text com o nome “numero_txt”. Adicione esse mc que você acabou de criar no layout do flash.
2.2. Desenhe um retângulo da largura das fotos (360 px no caso) e transforme-o num mc chamado “legenda_mc”. Agora entre no legenda_mc e crie uma layer. Nela, crie dois Dynamic Texts chamando-os de “titulo_txt” e “texto_txt”. Lembre-se de ativar os caracteres que for usar em Emded. Para ficar mais claro dê uma olhada na screen:
Agora posicione o legenda_mc no palco.
2.3. Por último, crie uma camada acima da legenda e desenhe um quadrado que ocupará a área do legenda_mc, depois transforme esse quadrado num movieclip chamando-o de “mascara_mc”. Coloque o tipo da layer como Mask. Adicione também uma layer acima de todas as outras, chamada Actions. O resultado final deverá ser esse:
3. Enquanto o layout fica fermentando, vamos avançar na parte mais temida: a programação! Vou fazer aos poucos pra irmos entendendo a lógica do código.
3.1. Captando os dados do xml, importando classes e já ajustando os botões vai e volta. Na timeline principal, na layer Actions, adicione:
CODE
//Importando as classes para fazer os movimentos dinâmicos
import mx.transitions.*;
import mx.transitions.easing.*;
//Criando o xml e fazendo ele ignorar espaços em branco
var tickersXML:XML = new XML();
tickersXML.ignoreWhite = true;
//Quando o xml carregar com sucesso executar as funções
tickersXML.onLoad = function(success:Boolean):Void {
//(o xml é carregado na última linha do script)
if (success) {
//Número total de tickers
n_tickers = tickersXML.firstChild.childNodes.length;
/*O ticker_atual será o último pois ao executar a função de
proximoTicker() ele passará automaticamente para o 1º resultado*/
ticker_atual = n_tickers;
//Acertando as funções dos botões
prox_btn.onRelease = function():Void {
//Se o fade das fotos tiver terminado
if (fotoIn.position == fotoIn.finish) {
//Vai para o próximo ticker
proximoTicker();
}
};
ant_btn.onRelease = function():Void {
if (fotoIn.position == fotoIn.finish) {
anteriorTicker();
}
};
//Chamando o primeiro ticker
proximoTicker();
/*******************************************************
Códigos do passo 3.2 serão adicionados aqui
*******************************************************/
} else {
//Caso dê errado o carregamento, avise
sobeLegenda();
legenda_mc.titulo_txt.text = "Ocorreu um erro";
legenda_mc.texto_txt.text = "Por favor entre em contato com a administração";
}
};
/*******************************************************
Códigos do passo 3.3 em diante serão adicionados aqui
*******************************************************/
//Carregando o XML e dando início ao processo
tickersXML.load("tickers.xml");
Vamos às considerações sobre o AS até agora. Primeiro a gente cria o objeto XML e a função que será executada quando carregar. Nela vem a parte “se tudo der certo” e depois “se acontecer algum erro”. Repare que nessa segunda parte existe uma função chamada sobeLegenda() que ainda não criamos, mas já dá pra ter a idéia de o que ela faz, certo?
Depois de carregarmos o XML contamos quantos tickers temos. A idéia é:
tickersXML – todo o documento|
firstChild – o primeiro nó do xml (<tickers>) que contém todas as informações|
childNodes – uma array que contém todos os nós com as informações (<ticker>)|
length – o tamanho da array, ou seja, quantos ticker temos
Se ficar alguma dúvida faça testes com o trace(), e sempre! Por exemplo: trace (tickersXML.firstChild); Veja a diferença do resultado do trace quando vai se adicionando as palavras-chave. É muito importante que você compreenda o que cada comando faz ao ler o XML.
Vejamos agora a função do prox_btn.onRelease. Ela é inteira dentro de um if, que verifica se o fade das fotos já terminou (para não dar mais de um fade ao mesmo tempo e dar pau). Se tiver terminado (o fade) ele passa para o próximo ticker. A mesma coisa é para o botão ant_btn, porém com a função de voltar um ticker.
Depois de programados os botões, o script chama o primeiro ticker.
3.2. Montando o menu para o internauta ir direto para algum dos tickers. Substitua o comentário do código anterior por:
CODE
//Criando o menu duplicando o quadradinho existente
//Deixando o quadradinho base invisível
menu._visible = false;
//Pegando a posição inicial _x do menu
var menu_x = menu._x;
//Definindo a distância entre os botões
var menu_dist = 25;
//Criando um laço que gerará os botões do menu. Ele executa uma vez para cada ticker.
for (var i:Number = 0; i < n_tickers; i++) {
//Duplicando o movieclip menu
//O depth é i+5 porque até o depth 4 existem mcs ocupando [fotomc1, fotomc2, legenda_mc, area_mc]
var menubtn:MovieClip = menu.duplicateMovieClip("menu" + i, i + 5);
//Movendo o botão duplicado no eixo x.
menubtn._x = i * menu_dist + menu_x;
//Número do ticker
menubtn.numero = i;
//Texto do botãozinho
menubtn.numero_txt.text = i + 1;
//Quando apertar o botão, mudar para ticker indicado
menubtn.botao.onRelease = function():Void {
//Se o fade tiver terminado
if (fotoIn.position == fotoIn.finish) {
vaiParaTicker(this._parent.numero);
}
};
}
Dentro do laço for são criados cópias do botãozinho e são adicionadas as propriedades deles. Primeiro a gente move o botão para onde queremos. Funciona assim: da primeira vez que o for é executado a variavel i vale 0.
Então o primeiro botãozinho será colocado na posição x =(0*25+58)=58 (supondo que menu_x seja 58).
O segundo será colocado na posição x=(1*25+58)=83 e assim por diante.
Cada mc recebe uma variável (numero) com o número do ticker que ele tem que chamar. Recebe também o texto que é colocado no DynamicText. O botão invisível funciona de modo parecido com o prox_btn. A diferença é que usa a função que vai direto para um ticker. Obs: o this._parent.numero pega a variável numero do pai do botão invisível, ou seja, o mc menu.
3.3. As funções de avanço e retrocesso. Agora vamos finalmente criar as funções proximoTicker(), anteriorTicker() e vaiParaTicker(numero_ticker). Substitua o comentário do primeiro código por:
CODE
//Função que passa para o próximo ticker
function proximoTicker():Void {
//Se o ticker atual não for o último, aumenta em 1, se for ele vai para 0
ticker_atual < n_tickers - 1 ? ticker_atual++ : ticker_atual = 0;
insereDados(ticker_atual);
//Limpando o intervalo de troca de tickers
clearInterval(ticker_intervalo);
}
//Função que passa para o ticker anterior
function anteriorTicker():Void {
//Mesmo esquema da outra função
ticker_atual > 0 ? ticker_atual-- : ticker_atual = n_tickers - 1;
insereDados(ticker_atual);
}
//Função que vai direto para um ticker, é o mesmo esquema das outras
function vaiParaTicker(numero_ticker:Number):Void {
ticker_atual = numero_ticker;
insereDados(ticker_atual);
}
//Função que insere os dados vindo do XML no nosso sitema
function insereDados(ticker_atual:Number):Void {
//Colocando titulo e texto na legenda
legenda_mc.titulo_txt.text = tickersXML.firstChild.childNodes[ticker_atual].childNodes[1].firstChild.nodeValue + " > " + tickersXML.firstChild.childNodes[ticker_atual].childNodes[0].firstChild.nodeValue;
legenda_mc.texto_txt.text = tickersXML.firstChild.childNodes[ticker_atual].childNodes[2].firstChild.nodeValue;
//Carregando a foto
carregaFoto(tickersXML.firstChild.childNodes[ticker_atual].childNodes[3].firstChild.nodeValue);
//Definindo o link para quando clicar na foto
area_mc.onRelease = function():Void {
getURL(tickersXML.firstChild.childNodes[ticker_atual].childNodes[4].firstChild.nodeValue, "_self");
};
}
Vamos entender como funciona a primeira linha do próximoTicker(). Ela é na verdade um if(){}else{} reduzido. Veja ele “desenvolvido”:
CODE
//Desenvolvido
if(ticker_atual < n_tickers - 1) {
ticker_atual++;
} else {
ticker_atual = 0;
}
//Reduzido
ticker_atual < n_tickers - 1 ? ticker_atual++ : ticker_atual = 0;
Isso pode ser visto apenas como um capricho, mas acho interessante mostrar essa outra forma para que reconhecam-a caso vejam em outro código. As demais linhas da função seguem colocando os textos na legenda, o link no onRelease da area_mc e chamando a função de carregar a foto, a próxima que veremos. Para ir esclarecendo as dúvidas em relação ao endereçamento das informações no xml, use e abuse do trace(). Coloque só a primeira palavra-chave e depois vá testando adicionando as demais. Assim ficará mais fácil ter clareza de como o ActionScript trabalha.
As duas outras funções são bem parecidas com a primeira, exeto pela manipulação da variável ticker_atual.
Uma observação em relação a primeira função: o clearInterval é para limpar o intervalo que foi criado na função de adicionar a foto no palco. Isso garante que só depois que a foto foi carregada é que o sistema começa a contar o tempo para carregar a próxima foto.
3.4. Carregando as fotos. Essa parte é um pouco complicada, tem que sacar como funciona o esquema de dois movieclips para carregar as fotos e dar os fades. Adicione esse código embaixo do código do passo 3.3.
CODE
//Criando os dois movieclips para carregar as fotos
this.createEmptyMovieClip("fotomc1", 2);
this.createEmptyMovieClip("fotomc2", 1);
//Posicionando os mcs no palco
fotomc1._x = fotomc2._x = area_mc._x;
fotomc1._y = fotomc2._y = area_mc._y;
//Definindo qual está em cima (por causa dos fades)
fotoCima = fotomc1;
//Colocando a legenda por cima das fotos
legenda_mc.swapDepths(3);
//Função que carrega a foto e cria os fades
function carregaFoto(scr:String):Void {
//Parando o fade da foto anterior caso ainda esteja ocorrendo
fotoIn.stop();
//Criando o mcloader
var mclFoto:MovieClipLoader = new MovieClipLoader();
//Carregando a foto
mclFoto.loadClip(scr, fotoCima);
//Quando terminar de carregar a foto
this.onLoadInit = function():Void {
//Chamar o próximo ticker
clearInterval(ticker_intervalo);
ticker_intervalo = setInterval(proximoTicker, 5000);
//Fazer o fadeIn com a foto de cima
fotoIn = new Tween(fotoCima, "_alpha", None.easeNone, 0, 100, 1, true);
//Quando terminar a transição de fotos
fotoIn.onMotionFinished = function():Void {
//Pegar a foto de cima e jogar para trás
if (fotoCima == fotomc1) {
//Tirando o clip do fotomc2 que irá para frente
mclFoto.unloadClip(fotomc2);
fotomc1.swapDepths(fotomc2);
//Ao ir pra frente estará preparado para receber outra foto
fotoCima = fotomc2;
} else {
//Mesma coisa, caso seja o fotomc2 que estiver em cima
mclFoto.unloadClip(fotomc1);
fotomc2.swapDepths(fotomc1);
fotoCima = fotomc1;
}
};
};
//Adicionando o listener ao mcloader
mclFoto.addListener(this);
}
Inicialmente criamos os mcs nos níveis 1 e 2, e colocamos a legenda por cima deles, no nível 4. Dentro da função nós criamos uma instância do MovieClipLoader. Dê uma lida nesse tutorial para saber mais. Após isso mandamos o MCL carregar a foto e definimos que quando o carregamento terminar o fade deve ser executado. O fade é feito através da classe Tween, tem um tutorial que explica essa classe bem detalhadamente também.
Quando terminar o carregamento da foto, repare que chamamos a função proximoTicker depois de um intervalo de 5 segundos (5000 milisegundos). Esse número pode ser trocado sem problemas.
Quando o fade termina nós temos a seguinte situação:
- um movieclip por cima com a foto recém-carregada
- um movieclip por baixo com a foto antiga
Dependendo de qual estiver por cima, nós descarregamos a foto do mc que estiver atrás e trocamos os dois de lugar, assim a gente terá um mc vazio pronto para receber outra foto e dar o fade.
3.5. Finalizando o código com as funções da legenda. Vamos criar agora as funções de sobeLegenda() e desceLegenda(), além de configurar estados padrão e o aparecimento da legenda.
CODE
//Fazendo com que a legenda suba quando o mouse estiver em cima da foto
area_mc.onRollOver = sobeLegenda;
area_mc.onRollOut = desceLegenda;
area_mc._alpha = 0;
area_mc.swapDepths(4);
//Pegando as posições da legenda
var leg_aparece = legenda_mc._y;
var leg_esconde = legenda_mc._y + legenda_mc._height + 1;
//Função que esconde a legenda com Tweens
function desceLegenda():Void {
var desceTween:Tween = new Tween(legenda_mc, "_y", Strong.easeOut, legenda_mc._y, leg_esconde, 1.5, true);
}
//Função que mostra a legenda com Tweens
function sobeLegenda():Void {
var sobeTween:Tween = new Tween(legenda_mc, "_y", Strong.easeOut, legenda_mc._y, leg_aparece, 1.5, true);
}
//Abaixando a legenda por padrão
legenda_mc._y = leg_esconde;
//Configurando a máscara da legenda
legenda_mc.setMask(mascara_mc);
Não tem muito segredo aqui. Apenas definimos quando a legenda aparece e como. Estude a classe Tween do Flash que você poderá aperfeiçoar e personalizar tanto o movimento da legenda quanto o aparecimento das fotos. É só trocar os parâmetros na hora de criar o Tween, o resto continua configurado. Prático, não?
Salve seu aquivo e dê um Ctrl+Enter para gerar e swf. Certifique-se de que o swf, as fotos e o xml estejam na mesma pasta. Agora está finalizada a parte de Flash! Pode testar que você verá seu lindo sisteminha já funcionando!
Observações sobre práticas de organização do AS. Esse pode não ser o exemplo mais (com o perdão da expressão) “webstandard” de Flash. Mas algumas coisas podem ser ressaltadas:
- Colocar sufixos nos nomes de instâncias (_mc, _txt, _btn). Além de facilitar a identificação de o que se trata, o flash lista automaticamente os métodos, eventos e propriedades desse objeto ajudando na hora de escrever seu script.
- Comentar o código. O comentário não serve só pra fazer tutoriais, serve para te orientar caso volte a trabalhar com o projeto e para orientar colegas de trabalho, se você trabalhar em equipes.
- Usar nomes coerentes nas funções. Ajudam você a entender o código mais fácilmente (como o sobeLegenda, no começo da explicação do tuto).
- Usar uma variável para o número total no for, exemplo:
CODE
//Adequado
n_tickers = tickersXML.firstChild.childNodes.length;
for (var i:Number = 0; i < n_tickers; i++) {}
//Não adequado
for (var i:Number = 0; i < tickersXML.firstChild.childNodes.length; i++) {}
Isso aumenta o processamento desnecessariamente.
- Usar uma variável para se referir a um mc dinamicamente:
CODE
//Recomendado
var menubtn:MovieClip = menu.duplicateMovieClip("menu" + i, i + 5);
menubtn._x = i * 25 + 58;
//Não recomendado
menu.duplicateMovieClip("menu" + i, i + 5);
_root["menu"+i]._x = i * 25 + 58;
Pela mesma razão de carregar o processador desnecessariamente.
Bom galera, espero que tenham curtido essa primeira parte do tutorial e que o aproveitem para muitas coisas, inclusive para criar uma galeria de fotos! Se quiser é só tirar a parte de chamar a função proximoTicker() automaticamente que você terá uma ótima opção para mostrar seu portifolio!
Mas ainda não acabou. Vamos ver agora como gerar o xml por PHP pegando dados do MySQL.
Gerando o XML com PHP e MySQL
Esse tutorial é de nível básico-intermediário, pois alguns conceitos de PHP e de MySQL são exigidos.
Bom galera, vamos começar criando e populando a nossa tabela. Baixe as instruções em SQL para ficar mais fácil.
Depois de ter a tabela configurada, vamos criar o arquivo PHP que gerará o xml:
CODE
<?
//conectando ao mysql
$conn = @mysql_connect("localhost", "SEU LOGIN","SUA SENHA");
$db = @mysql_select_db("SEU BD", $conn);
//Selecionando todos os registros da tabela tickers
$sql = "SELECT * FROM 'tickers' ORDER BY 'id' ASC";
//Executando a instrução sql
$sql = mysql_query($sql);
//Pegando o numero de registros
$rst = mysql_num_rows($sql);
//Se tiver algum registro
if($rst > 0) {
// Abre / cria o arquivo tickers.xml com permissão para escrever
$xml = fopen("tickers.xml", "w");
//Escreve o cabeçalho e o primeiro nó do xml
fwrite($xml, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
fwrite($xml, "<tickers>\r\n");
//Para cada registro que tiver
for($i=0; $i<$rst; $i++) {
//Pegamos o valor de cada registro
$titulo = utf8_encode(mysql_result($sql,$i,"titulo"));
$area = utf8_encode(mysql_result($sql,$i,"area"));
$texto = utf8_encode(mysql_result($sql,$i,"texto"));
$foto = utf8_encode(mysql_result($sql,$i,"foto"));
$link = utf8_encode(mysql_result($sql,$i,"link"));
//Guardamos na variavel $conteudo as tags e os valores do xml
$conteudo = "<ticker>\r\n";
$conteudo .= "<titulo>$titulo</titulo>\r\n";
$conteudo .= "<area>$area</area>\r\n";
$conteudo .= "<texto>$texto</texto>\r\n";
$conteudo .= "<foto>$foto</foto>\r\n";
$conteudo .= "<link>$link</link>\r\n";
$conteudo .= "</ticker>\r\n";
//Escrevendo no tickers.xml
fwrite($xml, $conteudo);
}
//Finalizando com a última tag
fwrite($xml, "</tickers>");
//Fechando o arquivo
fclose($xml);
}
?>
Salve como xml.php e teste (lembre-se que a pasta precisa de permissão para gravação). Pronto, só isso. Depois você pode criar algum sistema para dar um update do MySQL e logo após chamar esse aquivo php para gerar novamente o XML. Mas não vou explicar isso aqui pois foge do escopo desse artigo.
Bom pessoal, agora está finalizado o artigo! Espero que tenham gostado e que aproveitem bastante.
Abraço, até a próxima!