Mini curso on-line AIR
Salve pessoal,
Esta saindo mais um mini-curso de AIR o qual será ministrado pelo Igor Costa.
Para mais informação clique aqui
Salve pessoal,
Esta saindo mais um mini-curso de AIR o qual será ministrado pelo Igor Costa.
Para mais informação clique aqui
Salve, pessoal! Estou voltando a escrever depois de um longo período de jejum nas publicações de novos artigos.
Pois bem, neste novo artigo irei demonstrar como criar um componente de paginação. Sabemos que em grande parte dos projetos é necessário amostrar diversos tipos de informação seguindo os padrões de Master Detail (Grid, List, etc.). Para este tipo de amostragem de dados, a paginação é um componente super importante, pois previne alguns problemas básicos, como:
A criação deste componente será dividida em dois artigos, sendo este o primeiro da série. Assim, neste primeiro desenvolveremos um componente que irá apenas paginar um montante de dados estáticos armazenados em um ArrayCollection, ou seja, criaremos toda a lógica para percorrer a lista e paginá-la em um componente do tipo lista (DataGrid, List, etc).
Já na segunda parte, faremos com que o servidor fique responsável pela tarefa de buscar e calcular o total de dados referentes à pesquisa. Desta maneira, nosso componente ficará responsável apenas por enviar qual a quantidade de dados a ser retornada e qual a faixa em que se encontra a sequência.
O principal motivo deste artigo estar dividido em duas partes é fazer com que o desenvolvedor entenda o funcionamento interno da paginação de dados, possibilitando a realização de melhorias durante a utilização do server-side se necessário.
Requisitos:
Nivel de dificuldade: 7.5
Agora vamos ao que interessa.
Iremos criar um componente customizado que estenda o Button, este será responsável por referenciar e exibir os dados referentes a uma página. Este componente é muito simples, o que realmente devemos observar são os seguintes pontos:
Segue o código:
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 | package com.imaster.impl { import com.imaster.event.PaginacaoEvent; import flash.events.MouseEvent; import mx.controls.Button; /** * * @author Fabiel Prestes * */ [Event(name="exibirPagina", type="com.imaster.event.PaginacaoEvent")] public class BotaoPagina extends Button { [Bindable] private var _pagina:int; [Bindable] private var _intervaloInicial:int; private var _evtPaginacao:PaginacaoEvent; public function BotaoPagina() { super(); } override protected function childrenCreated():void{ super.childrenCreated(); this.buttonMode = true; this.useHandCursor = true; /* Define a label do botao com o mesmo numero de pagina */ if(this.label == '') this.label = String(_pagina); } /** * Define a pagina a qual este botao deve amostrar os dados para o usuario. * @param int Numero da pagina */ public function set pagina(value:int):void { _pagina = value; } /** * Retorna o numero da pagina na qual este botao deve amostrar os dados. * @return */ public function get pagina():int { return _pagina; } /** * Define o intervalo Inicial que deverá ser amostrado na noav listagem * @param int Numero da pagina */ public function set intervaloInicial(value:int):void { _intervaloInicial = value; } /** * @return */ public function get intervaloInicial():int { return _intervaloInicial; } override protected function clickHandler(event:MouseEvent):void { super.clickHandler(event); if(this.selected){ _evtPaginacao = new PaginacaoEvent(PaginacaoEvent.EXIBIR_PAGINA); _evtPaginacao.botaoPagina = this; this.dispatchEvent(_evtPaginacao); } } } } |
Agora, com o componente BotaoPagina criado, iremos desenvolver nosso evento personalizado, que irá delegar e orquestrar as requisições feitas entre o BotaoPagina e nosso componente principal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package com.imaster.event { import com.imaster.impl.BotaoPagina; import flash.events.Event; /** * * @author Fabiel Prestes * */ public class PaginacaoEvent extends Event { public static const EXIBIR_PAGINA:String = "exibirPagina"; public var botaoPagina:BotaoPagina; public function PaginacaoEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) { super(type, bubbles, cancelable); } } } |
Abaixo está o código mxml que será a capa do componente de paginação principal, neste teremos os seguintes componentes:
Segue o código abaixo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version="1.0" encoding="utf-8"?> <mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" horizontalAlign="center" xmlns:impl="com.imaster.impl.*"> <mx:Metadata> [ExcludeClass] </mx:Metadata> <mx:Button id="bpPaginaAnterior" toggle="false" icon="@Embed(source='/assets/anterior.png')" useHandCursor="true" buttonMode="true"/> <mx:HBox id="containerBpIntermadiarios"/> <mx:Button id="bpProximaPagina" toggle="false" icon="@Embed(source='/assets/proxima.png')" useHandCursor="true" buttonMode="true"/> <mx:ComboBox id="cbIntevalo" width="60"> <mx:dataProvider> <mx:Object label="5" value="5"/> <mx:Object label="10" value="10"/> <mx:Object label="15" value="15"/> </mx:dataProvider> </mx:ComboBox> </mx:HBox> |
Agora daremos início à criação do componente que orquestrará toda a tarefa de manipulação da paginação. Este componente é bem simples, contudo requer atenção em alguns pontos, já que nesta primeira parte do artigo iremos criar toda a lógica de paginação e, no próximo artigo, será de responsabilidade do server-side.
Métodos principais:
Há outros métodos na classe, contudo os citados acima são os mais importantes, deixei todo o código comentado, assim ficará mais fácil tirar as dúvidas.
Segue o código:
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 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | package com.imaster.impl { import com.imaster.PaginacaoUI; import com.imaster.event.PaginacaoEvent; import flash.events.MouseEvent; import mx.collections.ArrayCollection; import mx.controls.listClasses.ListBase; import mx.events.ListEvent; /** * * @author Fabiel * */ public class Paginacao extends PaginacaoUI { [Bindable] private var _totalPorPagina:int = 5; [Bindable] private var _totalDados:int; [Bindable] private var _listaBase:ArrayCollection; [Bindable] private var _listaBaseAux:ArrayCollection; private var _bpAux:BotaoPagina; private var _bpAtual:BotaoPagina; private var _listaAlvo:ListBase; private var _botoesPagina:Array = []; private var totalBotoes:int; public function Paginacao() { super(); } override protected function childrenCreated():void{ super.childrenCreated(); /* Adicionando os Listeners */ this.bpPaginaAnterior.addEventListener(MouseEvent.CLICK, trateExibirPaginaAnterior, false, 0, true); this.bpProximaPagina.addEventListener(MouseEvent.CLICK, trateExibirProximaPagina, false, 0, true); this.cbIntevalo.addEventListener(ListEvent.CHANGE, trateTrocaIntervalo, false, 0, true); } override public function invalidateProperties():void{ super.invalidateProperties(); /* Inicializa a configuração da paginação */ configurarBotoesPagina(); } /** * @private * Fica escutando quando o usuario trocou o total de interva de dados a ser amostrado na lista * @param evt */ private function trateTrocaIntervalo(evt:ListEvent):void{ _totalPorPagina = cbIntevalo.selectedItem.value; /* Inicializa a configuração da paginação */ configurarBotoesPagina(); } /** * @private * Responsavel por configurar os botoes de paginação na tela. */ private function configurarBotoesPagina():void{ /* Calcula a quantidade de botoes que deverao ser criados baseado no total de dados e total de dados por pagina */ totalBotoes = Math.ceil(totalDados/totalPorPagina); /* Se houver BotoesPagina ja configurado no container, deve-se removelos para * recalcular o total de paginas */ if(containerBpIntermadiarios != null && containerBpIntermadiarios.getChildren() != null){ containerBpIntermadiarios.removeAllChildren(); _botoesPagina = []; } /* Realiza um loop criando os botoes */ for(var i:int = 1; i <= totalBotoes; i++){ /* Cria e configura o BotaoPagina */ _bpAux = new BotaoPagina(); _bpAux.toggle = true; _bpAux.pagina = i; _bpAux.intervaloInicial = (i - 1) * _totalPorPagina; _bpAux.addEventListener(PaginacaoEvent.EXIBIR_PAGINA, trateExibirPagina); _botoesPagina[i] = _bpAux; /* Se for o primeiro BotaoPagina criado deve-se configurar a lista de dados na componente tipo ListBase */ if(i == 1){ _bpAux.selected = true; _bpAtual = _bpAux; configurarListaNaPagina(_bpAux); } /* Adiciona os botoes no container */ containerBpIntermadiarios.addChild(_bpAux); } } /** * @private * Configura e renderiza os dados Base para ser amostrado na tela levendo-se em consideração * o intervalo passado. * @param intervloIncial * */ private function configurarListaNaPagina(bpAtual:BotaoPagina):void{ _listaBaseAux = new ArrayCollection(); /* para cada Loop é copiado o objeto que se encontra no intervalo passado como parametro */ for(var j:int = 0; j < _totalPorPagina; j++){ if(bpAtual.intervaloInicial + j < _totalDados) _listaBaseAux.addItem(_listaBase.getItemAt(bpAtual.intervaloInicial + j)); } /* Configurando os botoes de avançar e retornar */ if(bpAtual.pagina > 1){ configBpPaginaAnterior(); } else { configBpPaginaAnterior(false); } if(bpAtual.pagina == totalBotoes){ configBpProximaPagina(false); } else { configBpProximaPagina(); } /* Define o provider clonado e define na ListBase */ this._listaAlvo.dataProvider = _listaBaseAux; } /** * @private * Responsavel por ficar escutando quando o usuario deseja visualizar o conteudo de cada pagina */ private function trateExibirPagina(evt:PaginacaoEvent):void{ _bpAtual.selected = false; _bpAtual = evt.botaoPagina; configurarListaNaPagina(_bpAtual); } /** * @private * Responsavel por exibir os dados da paragina anterior. */ private function trateExibirPaginaAnterior(evt:MouseEvent):void{ /* Verifica qual a pagina em que esta para pegar a anterior */ var i:int = (_bpAtual.pagina >= 1) ? _bpAtual.pagina - 1 : 0; _bpAtual.selected = false; _bpAtual = _botoesPagina[i]; _bpAtual.selected = true; configurarListaNaPagina(_bpAtual); } /** * @private * Responsavel por amostrar os dados da proxima pagina */ private function trateExibirProximaPagina(evt:MouseEvent):void{ /* Verifica qual a pagina em que esta para pegar a proxima */ var i:int = (_bpAtual.pagina < (_botoesPagina.length - 1)) ? _bpAtual.pagina + 1 : _botoesPagina.length; if(i < _botoesPagina.length){ /* Desmarca o botao atual */ _bpAtual.selected = false; /* Recupera o proximo botao e marca o mesmo */ _bpAtual = _botoesPagina[i]; _bpAtual.selected = true; /* Configura a lista na pagina */ configurarListaNaPagina(_bpAtual); } } /** * Define o total de dados que serão amostrados em cada pagina * @param value * */ public function set totalPorPagina(value:int):void{ _totalPorPagina = value; } /** * Retorna o numero de dados que esta/serão amostrados na tela. * @return */ public function get totalPorPagina():int{ return _totalPorPagina; } /** * Define o total de dados que serão amostrados em cada pagina * @param value * */ public function set totalDados(value:int):void{ _totalDados = value; } /** * Retorna o numero de dados que esta/serão amostrados na tela. * @return */ public function get totalDados():int{ return _totalDados; } public function set listaAlvo(value:ListBase):void{ _listaAlvo = value; } public function get listaAlvo():ListBase{ return _listaAlvo; } /** * Define a lista que será utilizada para exibir na paginacao * @param value * */ public function set listaBase(value:ArrayCollection):void{ _listaBase = value; if(_listaBase){ _totalDados = _listaBase.length; } } public function get listaBase():ArrayCollection{ return _listaBase; } private function configBpPaginaAnterior(value:Boolean = true):void { this.bpPaginaAnterior.enabled = value; } private function configBpProximaPagina(value:Boolean = true):void { this.bpProximaPagina.enabled = value; } } } |
Código Main.mxml
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:impl="com.imaster.impl.*" width="500" height="300" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#909090, #EEEEEE]"> <mx:Style source="assets/style.css"/> <mx:ArrayCollection id="listContatos"> <mx:Object nome="Fabiel Prestes" email="fabiel.prestes@gmail.com"/> <mx:Object nome="Joao Prestes" email="joao.prestes@gmail.com"/> <mx:Object nome="Patricia Prestes" email="patricia.prestes@gmail.com"/> <mx:Object nome="Aline Rodrigues" email="aline@gmail.com"/> <mx:Object nome="Carolina almeida" email="carol@gmail.com"/> <mx:Object nome="Juaca Pato" email="jaca.pato@gmail.com"/> <mx:Object nome="Antonio Carlos" email="antonio@gmail.com"/> <mx:Object nome="Marcela M. M." email="marcelamm@gmail.com"/> <mx:Object nome="Ana Julia" email="ana@gmail.com"/> <mx:Object nome="Cecicia" email="cc@gmail.com"/> <mx:Object nome="Fernando B." email="fb@gmail.com"/> <mx:Object nome="Castro Alves" email="castro@gmail.com"/> </mx:ArrayCollection> <mx:DataGrid id="dgDados" width="300" height="200"> <mx:columns> <mx:DataGridColumn headerText="Nome" dataField="nome"/> <mx:DataGridColumn headerText="Email" dataField="email"/> </mx:columns> </mx:DataGrid> <impl:Paginacao totalPorPagina="5" listaBase="{listContatos}" listaAlvo="{dgDados}"/> </mx:Application> |
E é isso, pessoal, acabamos de criar um componente de paginação que realizará todo o trabalho de manipulação manualmente. Na segunda parte do artigo, vamos alterar e demonstrar como utilizar o server-side para facilitar.
Qualquer dúvida é só comentar ou enviar email.
Salve pessoal,
Neste artigo irei demonstrar como criar um componente visualizador de mensagens bem parecido com o que msn utiliza.
É muito comum hoje em aplicações Flex/Air a necessidade de transpor informações entre a app e usuário. A grande parte dos usuário não ficam satisfeitos quando ao realizar alguma tarefa o sistema exiba na parte central da aplicação uma caixa com texto e uns botôes. Há alguns fatores importantes que devem ser levados em consideração.
1 - Usuário não tem o costume de ler toda a informação contidas em alertas.
2 - O usuário não quer ter seu fluxo de trabalho interrompido por um alerta, que na grande parte do tempo ele não quer ler.
3 - Fica dificil em primeira instancia visual o usuario distinguir se significa um erro ou apenas mensagens de rotina como “Salvo com sucesso”.
Se pararmos para pensar melhor poderemos encontrar outros fatores importantes.
Uma solução elegante para este problema é a criação de um componente que possa passar a mensagem ao usuário de uma
forma que não impeça o fluxo de trabalho e ao mesmo tempo chame a atenção do usuário para a mensagem “informação”
que o sistema esteja passando.
Para este proposito iremos criar um componente de mensagem similar ao que o msn, twitter entre outros aplicativos utilizam.
Requisitos para o desenvolvimento do artigo:
* Ter Flex/Flash Builder ou outra IDE.
* Ter SDk 3 ou superior.
* Conhecimento em ActionScript e Mxml.
Nivel de dificuldade: 5
Certo agora vamos ao que realmente interessa.
Criar um projeto flex: “AlertaCustomizado” ou outro nome qualquer e com a seguinte estrutura.

Criar a classe AlertaUI.as. Esta é a classe que será exibida para o usuario, ou seja, será o componente principal.
Esta classe é relativamente simples, composta pelos seguintes componentes nativos do flex:
1 - O componente base será um Canvas.
2 - Teremos dois efeitos Parallel.
* createEffect = responsavel por exibir o componente alerta na tela, este será composto pelos efeitos Move e Fade.
* removeEffect = responsável por ocultar o componente de alerta da tela pai, este tambem será composto por dois efeitos o Move e o Fade. Poderiamos ter utilizado nos dois casos tanto no create quanto no remove o efeito Move, contudo para dar um pouco mais de elegancia utilizaremos o fade.
3 - Um componente Labelo qual iremos defini-lo como o titulo do nosso alerta.
4 - Um componente Text o qual conterá o conteudo do nosso alerta que desejamos apresentar ao usuário.
5 - Um componente Image para exibido ao lado do titulo do alerta.
Segue a baixo o codigo da classe AlertaUI.mxml o mesmo relativamente simples o unico detalhe é a vinculacao dos efeitos createEffect e removeEffect aos respectivos eventos do canvas.
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="200" height="100" styleName="fundoAlertaSucesso" paddingBottom="5" paddingLeft="5" paddingTop="5" paddingRight="5" verticalScrollPolicy="off" horizontalScrollPolicy="off" creationCompleteEffect="{createEffect}" removedEffect="{removeEffect}"> <mx:Style> .fundoAlertaSucesso{ borderStyle: applicationControlBar; fill-colors: #03A438, #6FCE8F; fillAlphas: 1, 1; highlightAlphas: 0, 0; drop-shadow-enabled: true; corner-radius: 5; } .fundoAlertaErro{ borderStyle: applicationControlBar; fill-colors: #E43434, #FCA5A5; fillAlphas: 1, 1; highlightAlphas: 0, 0; drop-shadow-enabled: true; corner-radius: 5; } </mx:Style> <mx:Script> <![CDATA[ [Bindable] protected var _titulo:String; [Bindable] protected var _conteudo:String; [Bindable] protected var _icone:String; ]]> </mx:Script> <!-- Criando e configurando os efeitos --> <mx:Parallel id="createEffect"> <mx:Move id="mvExibirAlerta"/> <mx:Fade/> </mx:Parallel> <mx:Parallel id="removeEffect"> <mx:Move id="mvOcultarAlerta"/> <mx:Fade/> </mx:Parallel> <mx:Label id="lbTitulo" width="100%" text="{_titulo}" fontFamily="Courier New" fontSize="14" fontWeight="bold" color="#FFFFFF" left="5" top="5"/> <mx:Text id="tConteudo" htmlText="{_conteudo}" fontFamily="Courier New" fontSize="12" left="5" top="30" right="5" bottom="5"/> <mx:Image width="20" height="20" right="5" top="5" id="imgIcon" source="{_icone}" visible="{_icone != null}"/> </mx:Canvas> |
- Com o nosso esqueleto do nosso alerta pronto agora iremos definir as funcionalidades para o mesmo. Mas para isso iremos criar uma classe que extenda AlertaUI.mxml. Esta classe sim pode parecer complexa mais é muito simples requer apenas um pouco de atenção para alguns detalhes, vamos a eles:
1 - Metodo show este tem o mesmo intuito do metodo Alert.show, ou seja, exibir o componente na tela. Este pode receber até 5 paramentros:
* Titulo = Define o titulo que será exibido no componente.
* Conteudo = Define o conteudo que será exibido dentro do componente Text.
* TipoAlerta = Este irá definir qual o style que será utiliazado no Alerta.
Digamos que você queira que quando ocorrer um erro na aplicação seja exibido um alerta com um estilo diferente para chamar a atenção do usuário ou que quando ocorra algo rotineiro como: “Cadastro salvo com sucesso” etc seja exibido um alerta também com um estilo diferente, nesta situação este parametro é de suma importancia. Pois aqui voce poderá criar diferentes Style.css e defini-los da forma que bem entender. Neste artigo para exemplo didático irei criar apenas dois Style um identificando ERRO e outro SUCESSO.
* Duracao = Define o tempo em segundos que o alerta ficará disponivel para o usuário, o padrão será 3s.
* Icone = Define um icone a ser amostrado ao lado do titulo.
Assim o metodo show terá as seguintes responsabilidades:
* Instanciar uma nova variavel Alerta.
* Configurar o alerta criado baseado nos argumentos passados, como: Titulo, Icone, tipo do style etc..
* Executar o metodo PopUpManager.addPopUp passando como paramentro o alerta criado.
* E por ultimo e muito importante. Avisar ao gerenciador de Alerta (o qual irei falar em breve) que foi criado um novo alerta e o mesmo esta sendo exibido na tela.
2 - Metodo onCreate este é o segundo metodo mais importante do componente. O onCreate esta vinculado ao CREATION_COMPLETE, assim quando todos os componentes do alerta for criado o mesmo irá terminar de realizar algumas configuraçoes que somente é possivel neste estágio são elas:
* Definir o X e o Y do alerta, ou seja, definindo onde o alerta será exibido na tela. Para efeito didático irei abordar a mesmo localição do MSN no canto inferior direito, contudo esta é uma funcionalidade que você poderá futuramente customizar para ser exibido em outros locais.
* Configurar o efeito Move do createEffetc. Assim se já estiver sendo exibido um alerta na tela deverá ser levando em consideração a posição Y do novo alerta para que este não fique sobreposto ao antigo. Assim precisamos apenas configurar o yFrom e o yTo.
* Configurar o efeito Move do removeEffetc para indicar o yTo do mesmo, este irei definir sempre o Y da altura do Application.
* Irá ser adicionado dois listeners:MouseEvent.ROLL_OVER e MouseEvent.ROLL_OVER. neste dois efeitos que estara a jogado do alerta.
Sera bem comum o sistema exibir um alerta e o usuario nao conseguir ler todo o conteudo do alerta ate o mesmo fechar, para resolver este problema iremos fazer com que quando o usuario colocar o mouse em cima do alerta o mesmo nao ira ser ocultado mesmo que o tempo de 3 segundos seja atingido e que quando o usuario remover o mouse do alerta este sera ocultado imediatamente.
* Criando e configurando um timer para o Alerta. Este ira marcar quando o alerta devera ser ocultado.
3 - Metodo fecharAlerta este apenas remove da tela o alerta e avisa o gerenciador de alerta que o mesmo foi removido da tela.
Segue o codigo do Alerta.as
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 122 123 124 125 126 | package com.fabielprestes.views.impl { import com.fabielprestes.views.AlertaUI; import flash.display.DisplayObject; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.utils.Timer; import mx.core.Application; import mx.events.FlexEvent; import mx.managers.PopUpManager; /** * Responsavel por exibir e controlar o componente de alerta na tela. * * @author Fabiel Prestes */ public class Alerta extends AlertaUI { private var _novaAltura:int; private var _duracao:int = 3000; private var _timerOcultarAlerta:Timer; public static var ALERTA_SUCESSO:int = 0; public static var ALERTA_ERRO:int = 1; public function Alerta() { super(); this.addEventListener(FlexEvent.CREATION_COMPLETE, onCreate); } /** * @private * Espera o alerta ser totalmente criado para seguir o fluxo de configuraçao de posicionamento. * @param evt */ private function onCreate(evt:FlexEvent):void { /* Definindo o local onde o alerta será exibido, * Por simplicidade irei adotar o mesmo padrao do MSN, Twitter e outros, ou seja, * no canto inferior direito da tela * * Define o X, para isso pega-se o tamanho total da tela - o tamanho do nosso alerta - um gap qualquer. * Define o Y, para isso pega-se a (altura total da tela - um gap qualquer) - (a altura do nosso alerta * total de alerta visiveis na tela) */ this.x = Application.application.width - this.width - 5; this.y = (Application.application.height - 5) - (this.height * GerenciadorAlerta.getInstance().totalAlertaVisivel); /* Configurando os efeitos de MOVE. */ this.mvExibirAlerta.yFrom = Application.application.height; this.mvExibirAlerta.yTo = y; this.mvOcultarAlerta.yTo = Application.application.height; /* Configurando o eventos do MOUSE * * Apos o alerta ser exibido o mesmo ficará visivel apenas por um determinado tempo. * Desta maneira caso o demore para ler a msg o alerta será ocultado, para que isso nao aconteça * iremos definir que quando o usuario colocar o mouse em cima o alerta o mesmo fica disponivel ate * que o usuario retire o mouse de cima do alerta. */ this.addEventListener(MouseEvent.ROLL_OVER, function():void { _timerOcultarAlerta.removeEventListener(TimerEvent.TIMER_COMPLETE, fecharAlerta); }); this.addEventListener(MouseEvent.ROLL_OUT, function():void { fecharAlerta(null); }); /* Configurando o Tempo 'Timer' no qual o alerta ficará disponivel antes de ser ocultado */ _timerOcultarAlerta = new Timer(_duracao, 1); _timerOcultarAlerta.addEventListener(TimerEvent.TIMER_COMPLETE, fecharAlerta); _timerOcultarAlerta.start(); /* Ao sair deste metodo o efeito Parallel que nos deixamos como Bindable no creationCompleteEffect da Tela * será ativado */ } /** * @private * Remove o alerta da Tela. * Neste momento o efeito Parallel que nos deixamos como Bindable no removedEffect da Tela * será ativado * @param evt */ private function fecharAlerta(evt:TimerEvent):void{ PopUpManager.removePopUp( this ); /* Avisa o gerenciador que foi removido um Alerta */ GerenciadorAlerta.getInstance().alertaRemovido(); } /** * Responsavel por criar, configurar e exibir o Alerta tendo como base os argumentos como referencia. * * @param titulo Define o titulo a ser exibido no componente * @param conteudo Define o conteudo do alerta * @param tipoAlerta Define o style do alerta * @param duracao Define a duracao em segundos que o alerta ficará visivel para o usuario. Padra 3000 '3s' * @param icone Define um icone para ser exibido no alerta * @return a instancia do alerta criado e exibido; */ public static function show(titulo:String, conteudo:String, tipoAlerta:int = 0, duracao:int = 3000, icone:String = null):Alerta { var alerta:Alerta = new Alerta(); alerta._titulo = titulo; alerta._conteudo = conteudo; alerta._icone = icone; alerta._duracao = duracao; /* Define o Style do Alerta pelo tipo. * O padrao será sempre o fundoAlertaSucesso */ if(tipoAlerta == ALERTA_ERRO) alerta.setStyle('styleName', 'fundoAlertaErro'); /* Exibe o alerta na tela */ PopUpManager.addPopUp(alerta, DisplayObject(Application.application), false); /* Avisa o gerenciador que foi criado um novo alerta */ GerenciadorAlerta.getInstance().alertaCriado(); return alerta; } } } |
- Criando Gerenciador de alertas, este tem a finalidade de armazenar todos os alertas que estao sendo exibidos no momento, isso se deve ser feito para que quando o metodo onCreate for configurar os eventos ele calcule exatamente a posicao com que o novo alerta devera ser exibido. O gerenciador sera um Singletom para estas informacoes estarem visiveis e unicas para toda a aplicacao.
Segue o codigo GerenciadorAlerta.as
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 | package com.fabielprestes.views.impl { /** * Classe responsavel por gerenciar os alertas que estao visiveis ao usuario. * Esta classe será um Singleton. * * @author Fabiel Prestes */ public class GerenciadorAlerta { private static var _instance:GerenciadorAlerta; private var _totalAlertaVisivel:int = 0; private var _totalAlertaVisivelAux:int = 0; public function GerenciadorAlerta(type:PrivateGerenciadorAlerta) { if (type == null) { throw new Error("Erro: Não é possivel instancia GerenciadorAlerta, já que este é um Singleton."); } } /** * Retorna a instancia unica da classe GerenciadorAlerta */ public static function getInstance():GerenciadorAlerta { if (_instance == null) _instance = new GerenciadorAlerta(new PrivateGerenciadorAlerta()); return _instance; } public function alertaCriado():void { _totalAlertaVisivel++; _totalAlertaVisivelAux++; } public function alertaRemovido():void { _totalAlertaVisivel--; if(_totalAlertaVisivel <= 0) _totalAlertaVisivelAux = 0; } /** * Retorna o total de alerta que esta visivel para o usuario na tela */ public function get totalAlertaVisivel():int { return _totalAlertaVisivelAux; } } } internal class PrivateGerenciadorAlerta { public function PrivateGerenciadorAlerta() { } } |
- Criaremos uma classe teste que ira exibir quantro tipos de alerta. Alerta de sucesso com e sem imagem e Alerta de erro com e sem imagem.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal"> <mx:Script> <![CDATA[ import com.fabielprestes.views.impl.Alerta; ]]> </mx:Script> <mx:Button click="Alerta.show('Teste Sucesso', 'Conteudo teste')" label="Alerta Sucesso"/> <mx:Button click="Alerta.show('Teste Sucesso', 'Conteudo teste', Alerta.ALERTA_SUCESSO, 3000, 'assets/user.gif')" label="Alerta Sucesso Com Imagem"/> <mx:Button click="Alerta.show('Teste Erro', 'Conteudo teste', Alerta.ALERTA_ERRO)" label="Alerta Erro"/> <mx:Button click="Alerta.show('Teste Erro', 'Conteudo teste', Alerta.ALERTA_ERRO, 3000, 'assets/user.gif')" label="Alerta Erro Com Imagem"/> </mx:Application> |
E isso ai pessoal uma maneira simples e facil de se criar alertas como o do Msn, Twitter, gtalk etc…
Agora e so customizarem da melhor maneira.
Este componente foi baseado em alguns aspectos em componentes já existentes como o : Notification .
Qualquer duvida ou sugestao enviar comentarios.

Na próxima sexta-feira (2/10) (oops sexta-flex) vamos ter mais um convidado especial que vai falar para nós sobre os seus frameworks Away3D e Away3D Lite. Rob Bateman é londrino e adora o mundo 3D. Ele vai apresentar sobre o framework e como ele pode ajudar a criar ambientes 3D na plataforma Flash.
Palestra: Explorando o fator Z com Away3D e Away3D Lite
Palestrante: Rob Bateman
Sempre no mesmo horário: das 09:00 AM até as 10:00 horário de Brasília.
Endereço para acesso: http://experts.na3.acrobat.com/palestras/
Palestra em inglês.
Salve pessoal,
Neste artigo irei mostrar a vocês uma funcionalidade muito util e bem conhecida por alguns e um tanto desconhecida para outros é o “filterFunction”.
O FilterFunction permite criar e aplicar filtros de visões em ArrayCollection e XMLListCollection fazendo como base alguns criterios de busca. Este é muito útil quando você quer filtar e exibir ao mesmo tempo os dados contidos em algum armazenado ou componente como DataGrid, List, etc. Esta função é muito semelhante á um Auto Complete.
Para demonstrar esta fucionalidade irei demonstra-la em um exemplo real de projetos.
Iremos então criar um componente de busca de contatos de agenda o fluxo para este é muito simples.
Vejamos o seguinte senário:
A pizzaria Moda da Casa quer melhorar o atendimento dos pedidos de encomendas de pizza, para isto ela deseja enquanto o atendente fala com o cliente ele possa fazer uma busca no sistema pelo nome do cliente para pegar os dados pessoais do mesmo.
Para atender esta necessidade iremos criar um simples componente de filtro. o componente será estruturado da seguinte maneira, terá um campo textinput para informar o nome do cliente e um data grid que terá todos os clientes da pizzaria, desta maneria assim que o usuario digitar uma letra o sistema irá fazer um filtro no datagrid exibindo apenas os clientes que tenham as letras digitadas no campo nome.
Então mãos-a-obra.
Requisitos para o desenvolvimento do artigo.
* Ter Flex/Flash Builder ou outra IDE.
* Ter SDk 3 ou superior.
* Conhecimento em ActionScript e Mxml.
Nivel de dificuldade: 5
Passo 1: Criar um projeto Flex BuscadorCliente
Passo 2: Criar uma classe BuscadorCliente.mxml o qual será nosso componente principal.
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 | <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="onCreate()"> <mx:Script> <![CDATA[ import mx.collections.ArrayCollection; [Bindable] private var _dadosCliente:ArrayCollection; /** * Responsavel por instanciar o ArrayCollection e popular com clientes. */ private function onCreate():void { _dadosCliente = new ArrayCollection(); _dadosCliente.addItem({nome: "Ana Maria", end: "Rua das uvas", fone: 5553323}); _dadosCliente.addItem({nome: "Ana Julia", end: "Rua melao", fone: 5551122}); _dadosCliente.addItem({nome: "Ana Paula", end: "Av das torres", fone: 5553654}); _dadosCliente.addItem({nome: "Maria Antonia", end: "Rua da roça", fone: 5557894}); _dadosCliente.addItem({nome: "Antonio da Silva", end: "Al. Joazeiro", fone: 5559658}); _dadosCliente.addItem({nome: "João Ferreira", end: "Rua do expedito", fone: 5551147}); _dadosCliente.addItem({nome: "Maria Gabriela", end: "Rua da bondade", fone: 5552258}); _dadosCliente.addItem({nome: "Ana Paula Beltrão", end: "Rua da experança", fone: 5553369}); _dadosCliente.addItem({nome: "João Paulo", end: "Av Flex", fone: 5554471}); _dadosCliente.addItem({nome: "Cecilia Duarte", end: "Av Java", fone: 5555528}); _dadosCliente.addItem({nome: "Carolina Alcantra", end: "Av Flash", fone: 5556639}); _dadosCliente.addItem({nome: "José da Silva", end: "Rua da solidão", fone: 5557741}); _dadosCliente.addItem({nome: "Juliana Correia", end: "Rua do chico", fone: 5558852}); _dadosCliente.addItem({nome: "Juliano Correia", end: "Rua da manha", fone: 5559963}); _dadosCliente.addItem({nome: "Aline Bressanim", end: "Rua da sacola", fone: 5551123}); _dadosCliente.addItem({nome: "Gisaleine Bressanim", end: "Rua do sem nome", fone: 5552231}); _dadosCliente.addItem({nome: "Rafael Korn", end: "Rua da tranquilidade", fone: 5553321}); _dadosCliente.addItem({nome: "Ozzy Osbourne", end: "Rua das laranjas", fone: 5554456}); _dadosCliente.addItem({nome: "Bob Marley", end: "Rua das palmeiras", fone: 5555564}); _dadosCliente.addItem({nome: "Vera Verão", end: "Rua Adobe", fone: 5556654}); _dadosCliente.addItem({nome: "Ricardo Rodrigues", end: "Rua Sun", fone: 5557789}); _dadosCliente.addItem({nome: "Luciano Augusto", end: "Av da solidao", fone: 5558897}); _dadosCliente.addItem({nome: "Josiane Milanes", end: "Av Paulo Mender", fone: 5559987}); _dadosCliente.addItem({nome: "Josi Padro", end: "Rua do Brasil", fone: 5559951}); _dadosCliente.addItem({nome: "Carmela Moraes", end: "Rua esqueci", fone: 5557753}); _dadosCliente.addItem({nome: "Patricia Aloha", end: "Rua Maranhão", fone: 5551159}); _dadosCliente.addItem({nome: "Patrik da Silveira", end: "Rua Chuva de Prego", fone: 5553357}); _dadosCliente.addItem({nome: "Marcelo Medeiros", end: "Rua das uvas", fone: 5559382}); _dadosCliente.addItem({nome: "Marcela Santos", end: "Rua das uvas", fone: 5551782}); _dadosCliente.filterFunction = encontreCliente; _dadosCliente.refresh(); } /** * O objeto Item é cada item que esta no data provider do DataGrid. * A cada vez que o usuario digita uma letra no campo nome esta função é executada * e retorna true caso ache um item ou false no caso de o Item não corresponder ao filtro. */ private function encontreCliente(item:Object):Boolean { var encontrado:Boolean = false; /* Crieterio do Filtro */ if (item.nome.toLowerCase().search(tiNomeCliente.text.toLowerCase()) != -1) return true; else return false; } ]]> </mx:Script> <mx:Form width="100%" paddingLeft="0" paddingRight="0"> <mx:FormItem width="100%" label="Nome Cliente"> <mx:TextInput id="tiNomeCliente" width="50%" change="{_dadosCliente.refresh()}"/> </mx:FormItem> </mx:Form> <mx:DataGrid width="100%" height="100%" dataProvider="{_dadosCliente}"> <mx:columns> <mx:DataGridColumn headerText="Nome" dataField="nome"/> <mx:DataGridColumn headerText="Endereço" dataField="end"/> <mx:DataGridColumn headerText="Telefone" dataField="fone"/> </mx:columns> </mx:DataGrid> </mx:Application> |
Na classe acima temos de pestar a atenção nas seguintes partes:
1. _dadosCliente.filterFunction = encontreCliente; Aqui é onde defino qual metodo de filter o ArrayCollection deve utilizar.
2. _dadosCliente.refresh(); Toda vez que chamo o metodo refresh este por sua vez irá chamar o nosso metodo de filtro.
3. change=”{_dadosCliente.refresh()}” Toda vez que o usuario realizar alguma alteração nos dados do textinpu este irá chamar o metodo refresh que por sua vez irá executar a função de filtro.
4. private function encontreCliente(item:Object):Boolean; Este é o metodo de filtro. O objeto Item é cada item que esta no ArrayCollection
A cada vez que o usuario digita uma letra no campo nome esta função é executada e retorna true caso ache um item ou false no caso de o Item não corresponder ao filtro.
5. [Bindable] private var _dadosCliente:ArrayCollection; É de suma importancia definir a metadata Bindable no Array pois desta maneira todas alterções feita neste o datagrid irá ouvir.
E é isso pessoal uma forma simples, facil e rapida de aplicar filtro em listas. Qualquer duvida com relação deixem seu comentário.