Adobe AIR 101 – Como posicionar a tela do meu App no sistema operacional?

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.

Deixe uma resposta

Conecte-se com:

O seu endereço de email não será publicado Campos obrigatórios são marcados *

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>