Navegação dinâmica e deeplinking com SWFAddress | FlashPedia

leitura do artigo >

12
mai

Navegação dinâmica e deeplinking com SWFAddress

Extendendo o exemplo do Leo sobre como utilizar o SWFAddress para habilitar o histórico e url dos sites em Flash, trago este exemplo para ensinar como trabalhar com SWFAddress e filmes externos, de forma dinâmica, acompanhe.

Comentários (3) Comentários(8) Categorias Action Script3, Classes, Destaques, HowTo, IDEs e APIs

Olá Amigos, mais uma vez peço desculpas por demorar tanto para escrever novos posts, todos nós andamos bem ocupados – acredito eu – o suficiente pra não termos muita disponibilidade, porém, prometo este ano – novamente – me dedicar mais.

Primeiro, navegue neste site por alguns segundos, depois volte.

Tempos atrás o Leo postou um excelente exemplo de como se trabalhar com SWFAddress no Flash, permitindo o Deeplinking e navegação por histórico, foi um excelente tutorial e ganhou até um espaço no site dos criadores do SWFAddress, http://www.asual.com.

No exemplo de hoje, que é bem mais extenso que o do Leo, mas não tão complicado, ensinarei como carregar filmes externos de forma dinâmcia (sem necessidade de recompilar o filme principal) e já incluir estes filmes no sistema de Deeplinking, abrindo caminhos para construção de um CMS baseado em Flash, então, sem enrolação, comecemos:

Índice:

1 – Resumo do funcionamento do SWFAddress
2 – Diagrama do funcionamento das Classes e deste exemplo
3 – Construção do Exemplo

1 – Resumo do funcionamento do SWFAddress

O SWFAddress é composto de dois frontends, um em JavaScript (SWFAddress.js) e outro em ActionScript (SWFAddress.as e SWFAddressEvent.as), que trabalham juntos para informar e responder a alterações na barra de endereços, através do uso de âncoras (#âncora), ex: (http://www.seusite.com/#ancora).

Como funciona?
O SWFAddress.js, uma vez anexado ao documento do site (index.html, por exemplo), faz repetidos testes verificando se foi alterada a âncora no endereço, se ele notar alteração irá disparar um evento informando que a âncora foi alterada (SWFAddressEvent.CHANGE) e informar o valor da âncora SWFAddressEvent.value, que serão basicamente o evento e o valor que utilizaremos nesta navegação.
Então no Flash nós devemos ouvir este evento e trabalhar com o valor da âncora, assim como no exemplo que o Leo fez, executando uma ação para cada âncora encontrada, através de um Switch.

Desvantagem visível
A Desvantagem principal do uso do Switch é que você precisa conhecer cada ação e cada filme e isso precisa ser recompilado cada vez que for adicionado um novo canal, imaginemos o seguinte exemplo:

Temos um site com 3 canais: Home, Sobre, Contato
Então teoricamente temos um Switch respondendo ao SWFAddressEvent.CHANGE, testando as âncoras e carregando estes filmes:

addEventListener(SWFAddressEvent.CHANGE, onChangeFunction)
function onChangeFunction(event:SWFAddressEvent):void
{
switch(event.value)
{
case  "/home/" :
loadFunction("home.swf");
break;
case  "/sobre/" :
loadFunction("sobre.swf");
break;
case  "/contato/" :
loadFunction("contato.swf");
break;
}
}

Então, como essa função é compilada no filme principal, para adicionar um novo canal, ou remover, precisaríamos remover ou adicionar uma linha na mesma e recompilar o filme principal. Isso acabou.

Com este exemplo, vocês terão como base um sistema dinâmico de carregamento de filmes externos em 1 nível (#/canal/), que não necessita carregar arquivos SWF através de funções Loader. Você navegará somente através dos canais, exemplo “navigateTo(‘/canal/’).


2 – Diagrama do funcionamento das Classes e deste exemplo

Agora já expliquei em tese como funciona o SWFAddress (Recomendo ler a documentação das Classes, pois ele oferece vários outros valores para serem utilizados, inclusivemente em multinível – #/canal/subcanal/item – , então não esperem tudo deste exemplo.

Então vamos ao que interessa:

DynamicNavigation (br.flashpedia.DynamicNavigation)

Este é o nome do pacote de Classes que desenvolvi para criar um sistema de navegação que permita que inúmeros canais sejam adicionados, em tempo de execução, ao sistema de navegação de um site em flash, proporcionando deeplinking a todos estes canais e ainda oferecendo um opcional de canal de erro (ex:404) para canais inexistentes ou âncoras mal digitadas.

Funcionamento (síntese):
Você adiciona canais a um navegador principal, e executa chamadas para estes canais através de seus deeplinks (/canal/). O navegador confere a existência de um canal consultando sua lista interna de canais, caso o canal exista, ele mostra o canal, caso não exista, ele mostra o canal de erro.
Um canal já carregado (existe ou de erro) não é carregado duas vezes, uma vez carregado ele é adicionado a uma segunda lista, pra que seja reaproveitado acelere o processo de navegação.
O filme principal também pode ouvir mudanças na barra de endereços, permitindo que você inicie o site diretamente em um canal específico ou que você navegue através da barra de endereços e botões avançar e voltar.

Fluxograma

Sistema de transições

Algo que todos estamos acostumados é com transições de entrada e saída para canais em sites em flash, pouca coisa são além de animações e interações com dados que montam a visualização final do conteúdo.

Este exemplo trabalha (da mesma forma que o Gaia) com transições de entrada e saída, disparadas por eventos obrigatórios, que interagem com o sistema para a troca de canais, seguindo obrigatoriamente o roteiro:

Cada canal carregado deve ouvir obrigatoriamente os eventos:

  • DynamicNavigatorEvent.TRANSITION_IN_START
    (Inicia a animação de entrada)
  • DynamicNavigatorEvent.TRANSITION_OUT_START
    (Inicia a animação de saída)

E disparar obrigatoriamente os eventos:

  • DynamicNavigatorEvent.TRANSITION_IN_COMPLETE
    (Informa o término da animação de entrada)
  • DynamicNavigatorEvent.TRANSITION_OUT_COMPLETE
    (Informa o término da animação de saída)

O Gaia Flash Framework trabalha desta mesma forma, porém estes eventos estão embutidos na Interface IPage, tornando obrigatório o uso de duas funções transitionIn e transitionOut, que ao fim chamam funções transitionInComplete e transitionOutComplete, que apesar de encapsuladas, fazem o mesmo processo de ouvir e disparar eventos.

Processo:

Ao navegar para um canal através do histórico ou da ação do usuário, o sistema irá checar se existe um canal atualmente carregado, se existir, ele dispara o evento DynamicNavigatorEvent.TRANSITION_OUT_START, ouvido pelo canal, que executará a transição de saída e ao término irá disparar o evento DynamicNavigatorEvent.TRANSITION_OUT_COMPLETE, informando ao sistema que ele já saiu e pode carregar outro canal.

O sistema carrega ou exibe da lista o canal invocado e dispara o evento DynamicNavigatorEvent.TRANSITION_IN_START, que ouvido pelo canal mostrado, executa a animação de entrada.

Caso não exista nenhum canal no ambiente (caso específico ao entrar no site) apenas o evento DynamicNavigatorEvent.TRANSITION_IN_START é disparado.

Classes e Objetos

  • br.flashpedia.DynamicNavigation.core
    • DynamicNavigator.as
      Classe principal do pacote, deve ser instanciada no filme principal, ela contém a lista de canais existentes no sistema e controla quais canais devem ser carregados ou reexibidos.
    • DynamicLoader.as
      Classe auxiliar, que carrega os filmes externos
  • br.flashpedia.DynamicNavigation.data
    • DynamicNavigatorData.as
      Classe auxiliar do DynamicNavigator que exibe dados sobre o carregamento dos filmes e o valor da âncora
    • DynamicLoaderData.as
      Classe auxiliar do DynamicLoader que exibe dados sobre o carregamento do filme externo e envia dados para o DynamicNavigatorData
    • DynamicItem.as
      Classe de objeto que representa cada canal do site, contém 4 propriedades e deve ser adicionada a lista do DynamicNavigator, obrigatoriamente.
      Lista de propriedades:

      • name: Nome amigável para cada item, ex: “canal”
      • label: Nome real do item, ex: “Nome do canal”
      • deeplink: String da url do canal, ex: “/canal/”
      • file: Arquivo .swf do canal, ex: “canal.swf”
  • br.flashpedia.DynamicNavigation.events
    • DynamicNavigatorEvent.as
      Classe de eventos disparados e ouvidos pelo sistema, pelo filme principal e pelos filmes externos
    • DynamicLoaderEvent.as
      Classe de eventos auxiliar, que informa dados sobre o carregamento dos filmes externos

Vantagens dos pacotes de Classes

Como citado anteriormente, usar switch para testar os valores do SWFAddress e realizar ações para cada valor tira a dinâmica pela necessidade da função switch conhecer previamente cada item a ser testado, esse problema de dinâmica é resolvido utilizando classes que usam como base a classe Dictionary, que apesar de ser a classe mais simples da ActionScript 3 API é a mais útil, porque, basicamente, posso adicionar chaves para valores usando strings e na prática, posso carregar uma lista de valores diferentes a cada execução.
Outra grande vantagem é que acaba aquele processo de criar uma função baseada em Loader e carregar swfs, agora você navega somente por urls, deixando o processo de carregamento (e consequentemente de exibição) por conta do sistema, nada mais de loadFunction(“movie.swf”).

Resumo do funcionamento das Classes Principais

  • DynamicNavigator
    A Classe DynamicNavigator contém dois objetos Dictionary, itens e loadedItens, o objeto itens contem uma coleção de DynamicItens, que são as representações de cada canal que existirá no site enquanto a loadedItens é uma coleção dos canais já carregados.
    Antes de iniciar a execução da Classe DynamicNavigator é obrigatoriamente necessário incluir objetos DynamicItem através da função addItem(item:DynamicItem) para que o DynamicNavigator saiba exatamente os nomes, os arquivos e os deeplinks de cada canal.
    Para navegar entre os canais, você utiliza a função navigateTo(“/canal/”) e então o DynamicNavigator cuidará de checar se existe um DynamicItem com esse link, carregando ou exibindo.
    O DynamicNavigator escuta as alterações na barra de endereços através do evento DynamicNavigatorEvent.CHANGE.
  • DynamicItem
    Um objeto DynamicItem é a representação de canal canal carregado e deve obrigatoriamente ser adicionado, o motivo dele existir é permitir que você crie novos itens a partir de arquivos xml, manualmente, em tempo de execuação.

Então, em resumo, pra utilizar os pacotes, no filme principal você deve:

  • Criar um objeto DynamicNavigator
    var navigator:DynamicNavigator = DynamicNavigator.getInstace()
  • Criar objetos DynamicItem (representações dos canais)
    var item:DynamicItem = new DynamicItem(name, label, deeplink, swffile)
  • Adicionar os objetos DynamicItem ao DynamicNavigator
    navigator.addItem(item)
  • Adicionar um ouvinte para a mudança de URL
    navigator.addEventListener(DynamicNavigatorEvent.CHANGE, navFunction);
    function navFunction(event:DynamicNavigatorEvent):void {navigator.navigateTo(event.navigatorData.anchorValue)}
  • Iniciar a execução da Classe DynamicNavigator (Indicando canais padrão e de erro, pode indicar os dois idênticos)
    navigator.init(‘/home/’, ‘/404/’);

Ok, chega de teoria e vamos a prática!

3 – Construção do Exemplo

Bom, vou considerar que todos tenham lido tudo que está escrito acima, que todos saibam utilizar um ClassPath e que todos saibam usar loops para criar uma lista de menus e fazer isso manualmente ou a partir de um XML, além claro, de que todos saibam fazer o download corretamente das classes necessárias e publicar os swfs utilizando o swfobject, anexando ao código html os script js e claro, que todos saibam ler a documentação que está completa no compactado para download, portanto: Não responderei a nenhuma dúvida a respeito disso, pois é pré-requisito obrigatório para quem quer trabalhar com DeepLinking.

Objetivo

Construir um site como esse http://www.flashpedia.com.br/deeplink com 4 canais, com uma transição simples de entrada e saída do conteúdo baseada na TweenLite (blog.greensock.com/tweenlite).

Criando o Filme Principal, menu e ouvintes: Main.as (Index.fla)

Correção

No Main.as os listeners do objeto DynamicNavigator (navigator) estavam colocados dentro do loop que criava o menu, erroneamente, os listeners devem ser colocados fora deste loop, como está escrito da linha 76 até a 82 do código abaixo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package br.flashpedia
{
	//Importando as classes do pacote necessárias para a MainClass
	import br.flashpedia.DynamicNavigation.core.DynamicNavigator;
	import br.flashpedia.DynamicNavigation.events.DynamicNavigatorEvent;
	import br.flashpedia.DynamicNavigation.data.DynamicItem;
	import br.flashpedia.DynamicNavigation.data.DynamicNavigatorData;
 
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
 
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
 
	/**
	 * Document Class de exemplo para o pacote DynamicNavigation
	 * @author Eder Lima
	 */
	public class Main extends MovieClip 
	{
		//criando a referência para o DynamicNavigator
		private var navigator:DynamicNavigator;
		public function Main():void 
		{
			if (stage) init();
			//Iniciando o filme
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void 
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			removeEventListener(Event.ADDED_TO_STAGE, init);
			//Utilizando (ou criando) a instância da Classe DynamicNavigator (Singleton)
			navigator = DynamicNavigator.getInstance();	
			//Executando a função que cria o menu e configura o navegador
			configureMenu();	
			//escondendo o loader
			info.visible = false;
		}
		private function configureMenu():void
		{
			for (var i:int = 0; i < 4; i++)
			{
				/*
				 * Criando 4 DynamicItens, que serão os canais do site
				 * Já existem 4 filmes com os nomes de canal0.swf, canal1.swf, etc
				 * Então basicamente uso o loop para criar os itens de acordo com isso
				*/
				var item:DynamicItem = new DynamicItem("canal" + i, "Canal " + i, "/canal-" + i + "/", "canal" + i + ".swf");
				//Adicionando cada DynamicItem craido a lista do navegador
				navigator.addItem(item);
				//Criando os botões de um menu, note que posso criar em processo separados dos DynamicItens
				var menu:MovieClip = new MyButton();
				//Rótulos para os menus, note a utilidade da propriedade "label" de cada DynamicItem
				menu.label.text = item.label;
				//Anexando uma propriedade comum para todos os botões, no caso, o deeplink, utilizando a propriedade deeplink
				//de cada DynamicItem (/canal-0/, /canal-1/, etc)
				menu.deeplink = item.deeplink;
				//Opções do Mouse
				menu.label.mouseEnabled = false;
				menu.buttonMode = true;
				//Posicionando os menus
				menu.y = 45;
				menu.x = 270 + ( i * (menu.width + 10));
				//Adicionando cada item de menu
				addChild(menu);
				//Adicionando o evento ao clicar sobre cada menu 
				//(utilizará a propriedade deeplink, comum a todos, para navegar entre os canais)
				menu.addEventListener(MouseEvent.CLICK, navigateOnClick);
			}
                        //Adicionando o ouvinte para as mudanças na url para o navegador
			Navigator.addEventListener(DynamicNavigatorEvent.CHANGE, onChange);
			//Mostrando o loader ao carregar
			navigator.addEventListener(DynamicNavigatorEvent.LOAD_START, showLoader);
			//Escondendo ao terminar
			navigator.addEventListener(DynamicNavigatorEvent.LOAD_COMPLETE, hideLoader);
			//Informando o percentual
			navigator.addEventListener(DynamicNavigatorEvent.LOAD_PROGRESS, showProgress);
			//Configurando o alvo padrão (MovieClip) do navegador, onde serão carregados ou mostrados os filmes
			//Existe um filme instanciado como "t" no palco do filme principal
			navigator.defaultTarget = t;
			//Configurando um nome padrão para o site
			navigator.siteTitle = "FlashPedia DeepLinking";
			//Iniciando o navegador e configurando os canais padrão e de erro
			//Leia a documentação sobre esses dois parâmetros
			navigator.init("/canal-0/", "/canal-0/");
		}
		//Função que responde ao clique sobre cada botão, utilizando a propriedade deeplink contida
		//em cada botão para navegar, utilizando a função navigateTo do navegador
		private function navigateOnClick(event:MouseEvent):void
		{
			navigator.navigateTo(event.target.deeplink);
		}
		//Função que responde as alterações na url (barra de endereços do navegador, histórico, etc)
		//Navega utilizando a mesma função navigateTo do navegador
		private function onChange(event:DynamicNavigatorEvent):void
		{
			navigator.navigateTo(event.navigatorData.anchorValue);
		}
		//Mostrando o loader
		private function showLoader(event:DynamicNavigatorEvent):void
		{
			info.visible = true;
		}
		//Escondento o loader
		private function hideLoader(event:DynamicNavigatorEvent):void
		{
			info.visible = false;
			info.text = "carregando...";
		}
		//Mostrando o progresso
		private function showProgress(event:DynamicNavigatorEvent):void
		{
			info.text = String("carregando... " + int(event.navigatorData.bytesLoaded/event.navigatorData.bytesTotal*100) + "%");
		}
	}
 
}

Criando os canais (Reaproveitando a mesma Classe para os canais, mudando apenas o conteúdo interno): Channel.as (canal0.fla, canal1.fla, etc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package br.flashpedia 
{
	import br.flashpedia.DynamicNavigation.core.*;
	import br.flashpedia.DynamicNavigation.data.*;
	import br.flashpedia.DynamicNavigation.events.*;
 
	import com.greensock.TweenLite;
	import com.greensock.easing.Strong;
 
	import flash.display.MovieClip;
	import flash.events.Event;
 
	/**
	 * ...
	 * @author Eder Lima
	 */
	public class Channel extends MovieClip
	{
		//Criando um objeto navigator
		private var navigator:DynamicNavigator;
 
		public function Channel() 
		{
			addEventListener(Event.ADDED_TO_STAGE, init);
		}
		private function init(event:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			//Utilizando a instância do navegador já criada no Index (Main.as)
			navigator = DynamicNavigator.getInstance();
			//Adicionando os dois ouvintes obrigatórios
			//Transição de entrada
			navigator.addEventListener(DynamicNavigatorEvent.TRANSITION_IN_START, transitionIn);
			//Transição de Saída
			navigator.addEventListener(DynamicNavigatorEvent.TRANSITION_OUT_START, transitionOut);
		}
		//Transição de entrada, executada ao fim do carregamento, assim que o filme é adicionado ao alvo
		//Deve obrigatoriamente, disparar o evento DynamicNavigatorEvent.TRANSITION_IN_COMPLETE ao final
		private function transitionIn(event:DynamicNavigatorEvent):void
		{
			TweenLite.to(f, 1, { alpha:1, ease:Strong.easeOut, onComplete:transitionInComplete } );
		}
		//Função, ao final da transição de entrada, que dispara o evento DynamicNavigatorEvent.TRANSITION_IN_COMPLETE
		private function transitionInComplete():void
		{
			navigator.dispatchEvent(new DynamicNavigatorEvent(DynamicNavigatorEvent.TRANSITION_IN_COMPLETE));
		}
		//Transição de saída, executada quando se troca o canal, 
		//Deve obrigatoriamente, disparar o evento DynamicNavigatorEvent.TRANSITION_OUT_COMPLETE ao final, 
		//Para informar ao navegador que pode fazer a chamada do próximo canal
		private function transitionOut(event:DynamicNavigatorEvent):void
		{
			TweenLite.to(f, 1, { alpha:0, ease:Strong.easeOut, onComplete:transitionOutComplete } );
		}
		//Função, ao final da transição de saída, que dispara o evento DynamicNavigatorEvent.TRANSITION_OUT_COMPLETE
		private function transitionOutComplete():void
		{
			navigator.dispatchEvent(new DynamicNavigatorEvent(DynamicNavigatorEvent.TRANSITION_OUT_COMPLETE));
		}
	}
 
}

Compile os arquivos, coloque num pasta, configure o index.html, anexe o js e publique no seu servidor ou em um servidor on-line.

Enjoy! ;)

Fontes:
SWFAddress: http://www.asual.com/swfaddress
Exemplo: http://www.flashpedia.com.br/deeplink
Documentação:http://www.flashpedia.com.br/deeplink/docs/

Download completo (Classes, exemplos(somente cs4), documentação, projeto)

Exemplos DynamicNavigation
Baixado 161 vezes
Tamanho 619.04 KB
Clique para fazer o download

Observações
Na criação da lista de menus, observem que existe um movieclip na biblioteca e obervem também que eu o fiz manulamente.
Fica pra vocês o desafio de usar isso com xml, experimentem fazer uma lista xml com os DynamicItens e removam linhas do xml.
Esse pacote, apesar de encapsular muitas funções e trabalho, não tem, em momento algum, o objetivo de ser uma solução final ou sequer de fazer frente ao GAIA, inclusive eu recomendo o uso dele para projetos maiores e multiníveis.
Utilize como fonte de estudos e extenda conforme sentir necessidade e claro, colabore divulgando suas alterações.

Até a próxima!

Postado em 12-05-2010 por Eder Lima
em Action Script3, Classes, Destaques, HowTo, IDEs e APIs

Share/Save/Bookmark

Comentários

  • Rodrigo - Ne disse:
    em 12 de maio de 2010

    Ótimo tutorial, Eder.
    Parabéns o/
    Irei segui-lo, e entender finalmente como o DeepLink funciona.
    :}

  • B'uno Monteiro disse:
    em 12 de maio de 2010

    UOW!
    nota 10, Eder!
    e como eu não poderia deixar de fazer… “Eita! não faltou o D!!!”
    XD

    Bons estudos.

  • Leo Cavalcante disse:
    em 12 de maio de 2010

    Muito bom mesmo, Eder.
    Go-go-go FlashPédia.

  • Guilherme Baptista disse:
    em 12 de maio de 2010

    Parabén Eder!

    Tutorial animal, muito bom.

    É bom saber que tem gente que realmente se importa em passar conhecimento pra frente.

    Com tutoriais muito bem feitos, detalhando tudo certinho, com exemplos, código fonte pra baixar e tudo mais.

    Desse jeito, só não aprende quem não quer. =p

    Abraços;

  • Igor Amendola disse:
    em 12 de maio de 2010

    muuuuuuuuuuuuito bom!!!
    nota 10!!! parabens :D

  • Pedro Lins disse:
    em 13 de maio de 2010

    Parabens Eder, inspirador!
    Nerd de ouro esse menino rapaz…

  • Hugo Vanderlei disse:
    em 13 de maio de 2010

    Grande Eder! muito bom o post.. parabens!

  • Uriel Juliatti disse:
    em 22 de julho de 2010

    Muito, mas MUITO bom mesmo esse tutorial!

    Agora estou tentando implementar um deeplinking mais avançado, tal como: canal-0/subcanal-1/etc..

    Abs!

    Uriel

 Escreva um Comentário

Seu nome

E-mail (não será publicado) (obrigatório)

Website

Comente

Spam protection by WP Captcha-Free