In attesa della prima release stabile di Flex 4 possiamo impratichirci con alcune delle novità già annunciate e disponibili nella beta dell'SDK. In questo articolo ci focalizzeremo sui layout, interessantissima funzionalità che introduce la possibilità (finalmente!) di scorporare completamente il layer di presentazione da quello di logica funzionale consentendoci perfino di incidere in modo marcato sulle metafore di interazione della nostra applicazione senza scomodarne le funzionalità.
La sessione sarà molto pratica e focalizzata sulla creazione di un certo numero di esempi, ognuno volto ad evidenziare alcune specifiche peculiarità di queste nuove API. È consigliata l'installazione dell'ultima versione di Flex Builder, ora rinominato in Flash Builder, la cui beta è disponibile per Mac e Windows.
La teoria dei Layout
Come potete aver intuito, anche perché questo termine è utilizzato con significato simile in altre tecnologie, un layout in Flex specifica come deve comportarsi il meccanismo di disposizione degli oggetti all'interno di un'applicazione. Questo però non si riduce al funzionamento classico, tipico del celeberrimo GridLayout
delle awt di Java, che comporta solo l'imposizione di alcune costrizioni e automatismi nel posizionamento degli elementi ma ad un interessante e potentissimo meccanismo che nasce dalla combinazione di coordinate spaziali e variabili definite dall'utente, consentendoci di implementare logiche di collocazione che variano nel tempo o al variare di specifici parametri.
I layout che Flex mette a disposizione sono quattro, scorriamoli brevemente:
Layout | Descrizione |
---|---|
BasicLayout | viene implementato di default dall'applicazione e si comporta in modo completamente trasparente delegando ai posizionamenti assoluti dei singoli elementi l'onere di presiedere la disposizione dell'interfaccia |
HorizontalLayout | come suggerito dal nome, questo layout dispone gli elementi orizzontalmente uno a fianco del successivo ignorando le proprietà spaziali dei singoli oggetti, come ad esempio gli attributi 'x ' e 'y ' |
VerticalLayout | esattamente come il precedente ma questa volta la disposizione viene fatta automaticamente sull'asse delle ordinate |
TileLayout | equivale, nella sua implementazione standard, ad un HorizontalLayout con in più la peculiarità di andare a capo di riga nel momento in le dimensioni dell'oggetto da posizionare superino quelle dello spazio residuo nella riga corrente |
Per testare questi quattro layout possiamo costruire una piccolissima applicazione (Flash Builder: File -> New -> Flex Project
) contenente il seguente codice:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo" minWidth="1024" minHeight="768">
<s:layout>
<s:BasicLayout/>
</s:layout>
<s:Button label="prova layout 1"/>
<s:Button label="prova layout 2"/>
<s:Button label="prova layout 3"/>
</s:Application>
ed eseguirla sostituendo di volta in volta la dichiarazione sul layout da usare con una delle quattro a disposizione.
È anche possibile specificare un layout per una particolare porzione della nostra applicazione includendo gli oggetti che ci interessano e la dichiarazione del layout in un tag <s:group>
.
Creare un layout da zero
Dopo questo breve intervallo teorico e introduttivo cominciamo ad approfondire il tema dei layout in Flex 4 creandone uno completamente nostro: PerspectiveLayout
. L'obiettivo di questo layout è disporre gli elementi secondo una linea di fuga distanziandoli sull'asse z uno dall'altro con l'idea di ottenere un effetto di profondità esteticamente convincente.
Per prima cosa creiamo un nuovo progetto Flex e inseriamo nel file MXML alcuni elementi che fungeranno da cavie per il nostro esperimento: in questo caso si tratta di alcune immagini, scaricabili qui, all'interno di un tag <s:list>
:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
xmlns:flex4layouts="it.html.flash.flex4layouts.*">
<s:List id="list" width="100%" height="100%"
labelField="label"
itemRenderer="spark.skins.spark.DefaultComplexItemRenderer">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:dataProvider>
<s:ArrayList>
<s:BitmapImage source="number1.jpg"/>
<s:BitmapImage source="number2.jpg"/>
<s:BitmapImage source="number3.jpg"/>
<s:BitmapImage source="number4.jpg"/>
<s:BitmapImage source="number5.jpg"/>
</s:ArrayList>
</s:dataProvider>
</s:List>
</s:Application>
Prima di proseguire eseguiamo il progetto per certificare la disposizione verticale degli elementi.
Il prossimo passo consiste nel creare la classe che rappresenta il layout (Flash Builder: File -> New -> ActionScript Class
); impostiamola con i seguenti parametri:
Parametro | Valore |
---|---|
Package | arbitrario, possiamo scegliere ad esempio it.html.flash.flex4layouts |
Name | PerspectiveLayout |
Superclass | spark.layouts.supportClasses.LayoutBase |
Premendo il pulsante Finish
verrà generato un nuovo file PerspectiveLayout.as
contenente quel poco codice necessario a effettuare gli import necessari, dichiarare la classe e descriverne il costruttore. A questo punto non ci resta che sovrascrivere la funzione 'updateDisplayList' che abbiamo ereditato da LayoutBase
modificandola a nostro piacimento in modo che operi sugli elementi suscettibili a questo layout.
Per ottenere l'effetto desiderato è necessario invocare su ogni oggetto in interesse il metodo setLayoutMatrix3D(m)
specificando nella variabile m una matrice che descrive le trasformazioni che vogliamo applicare. A seguire il codice risultante:
package it.html.flash.flex4layouts { import flash.geom.Matrix3D; import flash.geom.Vector3D; import mx.core.ILayoutElement; import mx.core.IVisualElement; import spark.layouts.supportClasses.LayoutBase; public class PerspectiveLayout extends LayoutBase { override public function updateDisplayList(width:Number, height:Number) : void { for (var i:int = 0; i < target.numElements; i++) { var element:ILayoutElement = target.getVirtualElementAt(i); var m3d:Matrix3D = new Matrix3D(); m3d.appendTranslation( (target.numElements-i)*5 + 50, 100, (target.numElements-i)*50 ); m3d.appendRotation(-30,Vector3D.X_AXIS); element.setLayoutMatrix3D(m3d,false); } } } }
Come possiamo notare la variabile m3d
, che contiene un'istanza della classe Matrix3D
, mette a disposizione una serie di metodi (appendTranslation
, appendRotation
e appendScale
) utilissimi nel mascherare la complessità che dovremmo affrontare impostando manualmente i valori di una matrice di trasformazione.
Per ammirare il risultato del nostro impegno non ci resta che modificare la dichiarazione di layout sostituendo a <s:VerticalLayout/>
il nostro <flex4layouts:PerspectiveLayout/>
ed eseguire il progetto.
Nella seconda parte dell'articolo vedremo come aggiungere un aspetto dinamico al nostro layout.
Un layout dinamico
In questo parte dell'articolo impareremo come rendere il nostro layout un pò più dinamico facendo in modo che uno slider posto sulla scena possa controllarne l'orientamento degli elementi. Incominciamo inserendo il componente HSlider
all'interno del file MXML aggiungendo il seguente codice appena dopo la chiusura del tag </s:List>
:
<s:HSlider id="axisSlider"
minimum="-30"
maximum="30"
value="10"
liveDragging="true"
width="300" />
Il passo successivo consiste nel fare in modo che PerspectiveLayout
possa essere influenzato da una variabile che poi andremo a gestire a livello di interfaccia; questo si traduce semplicemente nel creare una funzione setter che porti il nome che vogliamo dare all'attributo dinamico:
// Aggiungere questa funzione all'interno della classe PerspectiveLayout private var _angle:Number = 0; public function set axisAngle(value:Number):void { _angle = value; var layoutTarget:GroupBase = target; if (layoutTarget) { layoutTarget.invalidateSize(); layoutTarget.invalidateDisplayList(); } }
Le ultime due istruzioni di questa funzione obbligano l'interprete a ricalcolare il layout a fronte della modifica del valore dell'attributo che abbiamo deciso essere dinamico (il nome dell'attributo corrisponde al nome della funzione, in questo caso axisAngle
); questa operazione contempla anche che l'interprete chiami la funzione updateDisplayList
che ora andremo a modificare in modo che sia influenzata dalla variabile _angle appena valorizzata.
Per le semplici finalità di questo articolo, e per ottenere un effetto accattivante, è sufficiente sostituire con _angle
il -30
passato come parametro alla funzione m3d.appendRotation
ottenendo il seguente codice:
m3d.appendRotation(_angle,Vector3D.X_AXIS);
Come ultimo tocco non ci resta che aggiungere la valorizzazione dell'attributo axisAngle
all'interno della dichiarazione del layout nel file MXML, modifichiamo quindi il codice tra i tag <s:layout>
in modo da ottenere:
<s:layout>
<flex4layouts:PerspectiveLayout axisAngle="{axisSlider.value}"/>
</s:layout>
Eseguiamo il progetto e proviamo a spostare lo slider posizionato in alto per ammirare il frutto del nostro impegno:
Conclusioni
L'introduzione dei Layout ha segnato un grande passo avanti per quanto riguarda il paradigma di progettazione delle interfaccie nel mondo Flex, dall'anno prossimo sarà infatti possibile scorporare completamente la parte di presentazione da quella di business logic e, con l'aiuto di altre nuove features come ad esempio le Skin, riuscire finalmente a trasformare l'approccio a questa tecnologia ad oggi ancora troppo condizionata dai suoi passati come Flash.
Sono già disponibili sulla rete alcuni layout tridimensionali preconfezionati (ad esempio qui e qui) e spero che nel 2010 altri ne vengano creati fino alla realizzazione di un vero proprio database condiviso di layout e skin a disposizione della comunità di sviluppatori.
Prima di salutarvi vi ricordo che, allegato a questo articolo, troverete un archivio compresso contenente i sorgenti dell'applicativo descritto.