Olá.
Hoje eu gostaria de fazer meu primeiro post de códigos que desenvolvo, aqui no novo blog, e que podemk ser úteis a outras pessoas. Vou começar com duas classes que faço um uso considerável nos meus projetos em ActionScript 3.0. São as classes do package timeflow. Elas auxiliam no controle de ações que envolvem passagem do tempo. Vamos às classes e logo abaixo vou colocar alguns casos de uso para exemplificar seus usos.
Updater:
/** * @author Pedro Paulo Almeida * For usage details please visit http://www.pedropauloalmeida.com.br * This software is free and you can use or modify it as you need to. */ package br.com.pedropauloalmeida.timeflow { import flash.events.Event; import flash.events.EventDispatcher; import flash.utils.Timer; import flash.events.TimerEvent; public class Updater extends EventDispatcher { private var _interCall :Number; private var _timer :Timer; private var _loops :int; private var _step :int; static public const ON_UPDATE_TIMER:String = 'ON_UPDATE_TIMER'; static public const ON_UPDATE_FINISHED:String = 'ON_UPDATE_FINISHED'; /** * Constrói um novo objeto Updater. * Este objeto será usado para as transações de intervalo de tempo. * Ao construir ele tem um tempo default de intervalo de 10s. * */ public function Updater() { super(); this._interCall = 10000; } //=========================================================================== Métodos de criação de timers: /** * Cria um novo timer. * @param loops -> número de vezes que o timer vai se repetir antes de se encerrar * @param sec -> intervalo, em segundos, para o timer */ public function createFiniteTimer(loops:int = 1, sec:Number = 10):void { this.resetTimerSettings(); try { if (loops < 1) throw new UpdaterError("Criando um timer finito com loops = 0"); this._interCall = sec * 1000; this._loops = loops; this.doTimer(); } catch (e:UpdaterError) { //trace("catch: " + e); } } /** * Cria um timer 'infinito' * @param sec -> intervalo, em segundos, para o timer */ public function createInfiniteTimer(sec:Number = 10):void { this.resetTimerSettings(); this._interCall = sec * 1000; this.doTimer(); } /** * Cria um novo timer, infinito, com intervalos de minuto. * @param min -> de quantos em quantos minutos é o ciclo do timer */ public function createInfiniteMinuteTimer(min:int = 1):void { this.resetTimerSettings(); this._interCall = min * 60000; this.doTimer(); } /** * Cria um timer regressivo que roda de um step até "zero". * @param loops -> número de vezes que o timer vai se repetir * @param sec -> intervalo do ciclo do timer em segundos */ public function createRegressiveTimerUpTo(loops:int = 10, sec:Number = 1):void { this.resetTimerSettings(); this._step = loops; this._loops = loops; this._interCall = sec * 1000; this.doTimer(false); } //=========================================================================== Manipulação de timers: /** * Pára o timer deste Updater. */ public function stopTimer():void { if (this._timer == null) return; if (this._timer.running) this.endTimer(); } public function pauseTimer():Boolean { if (this._timer != null && this._timer.running) { this._timer.stop(); return true; } return false } public function restartPausedTimer(pro:Boolean = true):Boolean { var success:Boolean = false; try { if (this._timer == null || this._timer.running || this._step <= 0 || this._interCall <= 0) { throw new UpdaterError("Tentando restartar timer com step 0 ou interCall 0"); } this.doTimer(pro); success = true; } catch (e:UpdaterError) { success = false; } return success; } /** * Se o timer estiver rodando, manter o step e o target, mas com um novo * tempo de intervalo de delay. * @param sec -> novo intervalo do timer em andamento * @param pro -> se o timer tem contagem regressiva ou progressiva. Default = progressivo */ public function modifyTimerIntervalTo(sec:Number, pro:Boolean = true):void { try { if (!this.isRunning()) { throw new UpdaterError("Tentando modificar o intervalo de um timer que está parado"); } this._interCall = sec * 1000; this._timer.stop(); this.doTimer(pro); } catch (e:UpdaterError) { // erro de reinicialização do timer: //trace(e); } } public function isRunning():Boolean { if (this._timer == null) return false; return this._timer.running; } //=========================================================================== Private build timers: private function resetTimerSettings():void { this._step = 0; this._interCall = 0; this._loops = 0; if (this._timer != null) { this._timer.stop(); if (this._timer.hasEventListener(TimerEvent.TIMER)) { this._timer.removeEventListener(TimerEvent.TIMER, timerStep); this._timer.removeEventListener(TimerEvent.TIMER, regressiveStep); } this._timer = null; } } private function doTimer(pro:Boolean = true):void { this._timer = new Timer(this._interCall, this._loops); (pro) ? this._timer.addEventListener(TimerEvent.TIMER, timerStep) : this._timer.addEventListener(TimerEvent.TIMER, regressiveStep); this._timer.addEventListener(TimerEvent.TIMER_COMPLETE, endTimer); this._timer.start(); } private function endTimer(e:TimerEvent = null):void { if (this.hasEventListener(ON_UPDATE_FINISHED)) { this.dispatchEvent(new Event(ON_UPDATE_FINISHED)); } this.resetTimerSettings(); } //=========================================================================== Event flow: /** * Este método é chamado a cada ciclo do objeto timer * @param e -> evento TimerEvent */ private function timerStep(e:TimerEvent):void { this._step++; super.dispatchEvent(new Event(ON_UPDATE_TIMER)); if (this._loops > 0 && this._step == this._loops) { this._timer.stop(); this.endTimer(); } } /** * Este método é chamado a cada ciclo de um regressive timer * @param e -> evento TimerEvent */ private function regressiveStep(e:TimerEvent):void { this._step--; super.dispatchEvent(new Event(ON_UPDATE_TIMER)); if (this._step == 0) this.resetTimerSettings(); } //=========================================================================== Get Step: public function get step():int { return this._step; } //=========================================================================== ToString: override public function toString():String { var s:String = "Updater.as:\n"; s += "_interCall: " + _interCall.toString() + "\n"; s += "_timer: " + _timer.toString() + "\n"; s += "\n\n"; return s; } } }
Agora a classe UpdaterError, para os casos de erro com a aplicação:
Updater Error:
/** * @author Pedro Paulo Almeida * For usage details please visit http://www.pedropauloalmeida.com.br * This software is free and you can use or modify it as you need to. */ package br.com.pedropauloalmeida.timeflow { public class UpdaterError extends Error { public function UpdaterError(msg:String, id:int = 0) { super("UpdaterError: " + msg, id); } } }
Para os Usages vou tentar demonstrar as facilidades que a classe Updater têm sobre a classe Timer nativa no flash. Mas vamos pelo começo primeiro, hehe.
A primeira coisa a se fazer é importar as classes:
import br.com.pedropauloalmeida.timeflow.*;
Os dois primeiros métodos são semelhantes à classe Timer. Criam um timer que pode rodar por um determinado número de vezes ou até um número “n” de vezes:
// crio uma instância do Updater var updater:Updater = new Updater(); // adiciono um listener para cada ciclo da contagem para o método "stepTimer": updater.addEventListener(Updater.ON_UPDATE_TIMER, stepTimer); // adiciono um listener para o fim do ciclo da contagem para o método "endTimer": updater.addEventListener(Updater.ON_UPDATE_FINISHED, endTimer); /* nesse caso eu crio um timer finito em um total de 10 loops que serão executados a cada * 1 segundo. Note bem que nesse caso eu passo o tempo em SEGUNDOS e não em * milissegundos, como no Timer nativo do Flash. Isso porque normalmente eu geralmente * me sinto mais à vontade lendo tempos em segundos. Mas você pode ter valores menores * do que 1 segundo. Por exemplo, para meio segundo basta passar 0.5 */ updater.createFiniteTimer(10, 1); private function stepTimer(evt:Event):void { trace("o updater está no passo: " + updater.step); } private function endTimer(evt:Event):void { trace("o updater terminou sua contagem"); }
Existem outros métodos de criação de timers, com comportamentos semelhantes aos demonstrados acima:
createInfiniteTimer -> cria um timer infinito
createInfiniteMinuteTimer -> cria um timer infinito de um número ‘x’ em minutos
Outra possibilidade é o timer regressivo, que explico abaixo:
Você viu que pode obter em que momento da contagem do Updater ele se encontra com a propriedade “step”. Se você usa um timer progressivo, finito ou infinito, essa contagem começa com zero e vai até onde você especificar. Uma das coisas que a classe oferece é a contagem regressiva. Onde o step vai do número de loops total até 0 (zero). Basta chamar o método ‘createRegressiveTimerUpTo’.
// crio uma instância do Updater var updater:Updater = new Updater(); // adiciono um listener para cada ciclo da contagem para o método "stepTimer": updater.addEventListener(Updater.ON_UPDATE_TIMER, stepTimer); // adiciono um listener para o fim do ciclo da contagem para o método "endTimer": updater.addEventListener(Updater.ON_UPDATE_FINISHED, endTimer); // Crio uma contagem regressiva de '10' a '0' com intervalos de 1 segundo: updater.createRegressiveTimerUpTo(10, 1); private function stepTimer(evt:Event):void { trace("o updater está no passo: " + updater.step); } private function endTimer(evt:Event):void { trace("o updater terminou sua contagem"); }
Interessante não é? Outro método que senti falta no Timer nativo do flash foi a capacidade de dar um “pause” no Timer. Isso não fico de fora da nossa classe Updater:
Para pausar um timer, regressivo ou não, basta chamar o método ‘pauseTimer’. Isso vai fazer com que o Updater pare o Timer interno. Mas vai manter os ’steps’ e ‘loops’ da classe intactos. Para restartar o Timer de onde ele parou, basta chamar o método ‘restartPausedTimer’. Caso você esteja usando um timer de contagem regressiva, passe um parâmetro ‘false’ para o método, para que a contagem prossiga regredindo.
Caso você deseje que o timer se inverta, basta omitir o parâmetro. Como você pode ver, é possível transformar um timer de progressivo em regressivo apenas pausando e em seguida restartando o updater de acordo com o parâmetro que você especificar no restart!
// pausa o timer: var updater = new Updater(); updater.createFiniteTimer(10, 1); // pausando o timer: updater.pauseTimer(); // caso queira reiniciar, basta chamar updater.restartPausedTimer(); // se o timer for de contagem regressiva, parâmetro 'false': updater.restartPausedTimer(false);
Um dos features que mais gostei dessa classe, foi poder simplesmente mudar o “andamento” do timer em tempo de execução. Isso eu considero algo pra lá de útil e o Timer nativo do Flash também não oferece.
Para alterar o intervalo de execução, basta chamar o método ‘modifyTimerIntervalTo’, passando o novo intervalo em segundos e, novamente, ‘false’ se você estiver usando um timer regressivo.
/* altero o andamento do updater para meio segundo. Como o timer nesse exemplo é progressivo, omito o segundo parâmetro do método */ updater.modifyTimerIntervalTo(0.5);
Como você pode ver no código, temos vários ‘try/catch’ para tratamentos de erro. A classe UpdaterError é um extends da classe Error do Flash. Você pode descomentar e fazer tratamentos de erro customizados de acordo com suas necessidades. Pode também modificar a estrutura, fazendo com que o método dê o throw e o try/catch fique onde estiver a instância… enfim: você decide.
Caso você tenha tido problemas ou erros devido ao GesHi que uso para exibir os códigos no HTML, você pode clicar aqui e baixar as classes em formato .as.
Qualquer dúvida, basta postar um comentário ou enviar um email para blog@pedropauloalmeida.com.br
olá pedro, estou com um problema com a sua classe estou tentando usar ela no flex mas me dar erro nesta função
private function tempo():void{
var updater:Updater = new Updater();
updater.addEventListener(Updater.ON_UPDATE_TIMER, stepTimer);
updater.addEventListener(Updater.ON_UPDATE_FINISHED, endTimer);
updater.createFiniteTimer(10, 1);
}
Severity and Description Path Resource Location Creation Time Id
1046: O tipo não foi encontrado ou não é uma constante de tempo de compilação: Updater. zoo/src zoo.mxml line 19 1257353141267 24388
Olá, Michel.
Como estamos conversando por e-mail, espero mandar logo pra vc um exemplo em Flex.
Abraços.
pp