Hoje inicio uma série de posts sobre Adobe AIR, eu venho prometendo isso faz séculos, mesmo depois de ter colocado dois cursos de Adobe AIR on-line, sempre faltava aquele tempinho extra.
Nada melhor como uma ótima sexta-feira ensolarada de Sampa para começar essa série. O que é 101 séries?
Basicamente são 101 receitas de como você faz isso ou aquilo, seja em qualquer tecnologia.
O post inaugural da série seria, como posicionar a janela do meu App no sistema operacional?
É muito simples a solução. Como explicar essa facilidade? Quando você cria uma nova App no Flash Builder para a plataforma AIR, você geralmente usa o componente WindowedApplication, o WindowedApplication é a Raiz do App, você pode até trocar mais basicamente cada nova Janela Window ou Windowed que você adiciona no AIR, ele acaba indo para o systemManager, onde você pode administrar facilmente.
Cada classe Window fica armazenda no momento em que ela é criada, sendo assim o systemManager recebe elas e o NativeApplication, onde SystemManager é gerenciado pelo run-time AIR, ai é só fazer a continha básica da herança que você chegará ao resultado.
<?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="555" height="381"> <fx:Declarations> <!-- Place non-visual elements (e.g., services, value objects) here --> </fx:Declarations> <fx:Script> <![CDATA[ import spark.components.Window; protected function changeWindowPosition(event:MouseEvent):void { if(_x.text != '' && _y.text != ''){ nativeApplication.activeWindow.x = Number(_x.text); nativeApplication.activeWindow.y = Number(_y.text); } } ]]> </fx:Script> <s:Button x="62" y="134" width="137" height="31" label="Mover" click="changeWindowPosition(event)"/> <s:Form x="32" y="15"> <s:FormItem label="x"> <s:TextInput id="_x"/> </s:FormItem> <s:FormItem label="y"> <s:TextInput id="_y"/> </s:FormItem> </s:Form> </s:WindowedApplication> |
Veja o código acima, como eu sei que a Janela Atual é o Próprio App, então eu não preciso instanciar ela, já que ela está visível, basta eu usar a propriedade nativeApplication e janela ativa (activeWindow) e eu consigo chegar onde eu quero para move-la de posição.
Outro exemplo bem legal que se pode fazer é o uso de efeitos, veja o mesmo código abaixo, só que agora com efeitos.
<?xml version="1.0" encoding="utf-8"?> <s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="555" height="381" xmlns:interfaces="com.riacycle.interfaces.*"> <fx:Declarations> <interfaces:JanelaInterpolator id="interpola"/> <s:Sequence id="mover" target="{this}" duration="1000"> <s:Fade duration="300"/> <s:Animate> <s:SimpleMotionPath property="tamanho" valueTo="{rect}" interpolator="{interpola}"/> </s:Animate> </s:Sequence> </fx:Declarations> <fx:Script> <![CDATA[ private var rect:Rectangle = new Rectangle(); public function get tamanho():Rectangle { return nativeWindow.bounds; } public function set tamanho(value:Rectangle):void { nativeWindow.bounds = value; } protected function changeWindowPosition(event:MouseEvent):void { rect.width = nativeWindow.width; rect.height = nativeWindow.height; rect.x = Number(_x.text); rect.y = Number(_y.text); mover.play(); } ]]> </fx:Script> <s:Button x="62" y="134" width="137" height="31" label="Mover" click="changeWindowPosition(event)"/> <s:Form x="32" y="15"> <s:FormItem label="x"> <s:TextInput id="_x"/> </s:FormItem> <s:FormItem label="y"> <s:TextInput id="_y"/> </s:FormItem> </s:Form> </s:WindowedApplication> |
Explicando o código:
Veja bem, quando você usa efeitos na própria janela onde você está chamando a ação, basicamente ela vai dar estouro de pilha e não funciona, justamente por que o intervalo de tempo entre a chamada e a execução acaba sendo no mesmo momento, nem que você tenha que chamar por callLater, o que na prática nunca vai funcionar. Foi ai que acabei criando o interpolador para facilitar, a execução do efeito, pegando valores anteriores do nativeWindow e aplicando os novos valores do Rect que o efeito irá aplicar.
Aqui está o código do Interpolador.
package com.riacycle.interfaces { import flash.geom.Rectangle; import spark.effects.interpolation.IInterpolator; public class JanelaInterpolator implements IInterpolator { public function JanelaInterpolator() { } /** * * Funciona assim: * * Você começa com o valor x = 200 e y= 200; * E soma a fração em Delta que sofre mudanças repetidas entre o valor final e o valor inicial. * * Basicamente se um objeto começa na posição x=200 e y=200; * E você quer mudar para x=300 e y= 300; * * Você faz a interpolação do efeito somando o valor inicial + fração (valor Final - valor Inicial) * * Isso dá um incremento a posição inicial do objeto. * * A fração é a velocidade com que essas mudanças ocorrem, você pode incrementar elas ou não. * */ public function interpolate(fraction:Number, startValue:Object, endValue:Object):Object { return new Rectangle(startValue.x + fraction * (endValue.x - startValue.x), startValue.y + fraction * (endValue.y - startValue.y), startValue.width + fraction * (endValue.width - startValue.width), startValue.height + fraction * (endValue.height - startValue.height)); } public function increment(baseValue:Object, incrementValue:Object):Object { return new Rectangle(baseValue.x + incrementValue.x,baseValue.y + incrementValue.y, baseValue.width + incrementValue.width,baseValue.height + incrementValue.height); } public function decrement(baseValue:Object, decrementValue:Object):Object { return new Rectangle(baseValue.x - decrementValue.x, baseValue.y - decrementValue.y, baseValue.width - decrementValue.width, baseValue.height - decrementValue.height); } } } |
Outro problema é que você tem que criar um retangulo para re-posicionar a tela que você está fazendo as mudanças, uma vez que você cria essas proporções a própria nativeWindow ou nativeApplication sempre que muda de posição é alterado os valores, então o mais correto é pegar os bounds, área da janela atual e corrigir isso através de uma propriedade própria sua, retardando o processo.
Já que as mudanças sofridas pelo nativeWindow são imediatas, devido não ter o immediatePropagation(); Impedindo que elas ocorram, você tem que recorrer ao fato do Rect para se salvar desse pequeno problema.
Esse efeito acaba valendo também para modificar o tamanho da janela em si, assim como redimencionar o tamanho de acordo com o conteúdo.
