Un effetto piuttosto diffuso nelle applicazioni desktop, e in molte RIA, è l'effetto di semi-trasparenza di un pannello quando questo viene trascinato: gli stessi software Adobe utilizzano questo effetto per evidenziare all'utente quale pannello sta spostando.
In questo articolo vedremo come rendere semi-trasparente un elemento quando viene trascinato, aggiungendo anche un piccolo effetto di ombreggiatura, il tutto tramite Actionscript 3 (in Flex 3 e in Flash CS3).
Per visualizzare i file di esempio presenti nell'articolo è necessario il Flash Player 9 (o successivo).
Preparazione dello stage
Per prima cosa creiamo un nuovo progetto (File -> New -> Flex Project) dandogli un nome a piacere, quindi trasciniamo un'istanza del componente Panel (contenuto nella categoria Layout del pannello Componenti); tramite il pannello proprietà diamo un identificavo al nostro pannello, per esempio pannello1; facoltativamente è possibile impostare anche un titolo per il pannello ed eventuali altre proprietà, ma non sono parametri rilevanti per il nostro esempio.
Trascinamento di un oggetto
Ora che abbiamo inserito sullo stage l'oggetto a cui vogliamo applicare l'effetto, dobbiamo per prima cosa renderlo trascinabile: in Flex possiamo usare le proprietà dei tag MXML per impostare l'esecuzione di una funzione al verificarsi di un evento, nel nostro caso gli eventi che ci interessano sono mouseDown
(ovvero il click sul pannello) e mouseUp
(ovvero il rilascio del pulsante sinistro del mouse) che lanceranno rispettivamente l'inizio e la fine del trascinamento dell'oggetto cliccato.
I comandi per avviare e fermare il trascinamento in Actionscript 3 sono i medesimi delle precedenti versioni di Actionscript, ovvero startDrag
e stopDrag
.
Possiamo quindi impostare due funzioni, trascina e rilascia, associandole ai suddetti eventi:
Listato 1. Trascina e rilascia l'oggetto
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="400">
<mx:Script>
<![CDATA[
public function trascina(evt:Event):void{
evt.target.startDrag()
}
public function rilascia(evt:Event):void{
evt.target.stopDrag()
}
]]>
</mx:Script>
<mx:Panel x="66" y="10" width="250" height="100" layout="absolute" title="Pannello" id="pannello1" mouseDown="trascina(event)" mouseUp="rilascia(event)" mouseChildren="false">
</mx:Panel>
</mx:Application>
Notiamo gli eventi MouseDown
e mouseUp
nel tag MXML del componente Panel, mentre nelle due funzioni abbiamo sfruttato la proprità target degli eventi per sapere su quale oggetto ha cliccato l'utente, in questo modo potremo sfruttare facilmente le funzioni anche per altri eventuali pannelli, come vedremo in seguito.
È da evidenziare nel codice anche l'impostazione della proprietà mouseChildren
a false: questo impedisce che l'evento del click del pulsante venga recepito dagli elementi interni al pannello (per esempio il titolo), situazione che potrebbe causare degli errori o degli effetti indesiderati in quanto, per esempio, potrebbe essere trascinato non l'intero pannello, ma un elemento interno a esso.
Il risultato del codice appena visto è il seguente:
Trascinamento del pannello
Impostazione della trasparenza e dell'ombreggiatura
Possiamo impostare molto semplicemente la trasparenza tramite la proprietà alpha (che, ricordiamo, in Actionscript 3 ha un range compreso tra 0 e 1) mentre per l'ombreggiatura possiamo affidarci al filtro DropShadow. Ecco come modificare le funzioni trascina e rilascia:
Listato 2. Aggiunge trasparenza e ombreggiatura
public function trascina(evt:Event):void{
evt.target.startDrag()
evt.target.alpha = .6
var filtro:DropShadowFilter = new DropShadowFilter()
filtro.alpha = .3
filtro.distance = 30
evt.target.filters = [filtro]
}
public function rilascia(evt:Event):void{
evt.target.stopDrag()
evt.target.alpha = 1
evt.target.filters = []
}
Come possiamo vedere, al click sul pannello la trasparenza viene impostata al 60% (0,6), viene quindi creata una nuova ombra con la trasparenza al 30% (0,3) e una distanza di 30 pixel, quindi il filtro viene applicato all'elemento cliccato grazie alla proprietà filters. Quando, invece, il mouse viene rilasciato, la trasparenza dell'elemento che era stato cliccato viene riportata al 100% (1) e il filtro DropShadow viene rimosso dalla clip.
Mantenere in primo piano il pannello cliccato
Nel nostro esempio, finora, abbiamo utilizzato un solo pannello, ma utilizzando più elementi avremmo un problema di sovrapposizioni, infatti, un pannello, durante il trascinamento, potrebbe risultare sottostante agli altri.
Uso di più pannelli con problemi di profondità
Come si può vedere, il Pannello 3 è posto sopra agli altri e tale rimane anche durante il trascinamento degli altri pannelli.
Il codice relativo a questo esempio è molto semplice; notiamo come le funzioni utilizzate per il trascinamento dei vari pannelli sono sempre trascina e rilascia, questo perché grazie all'utilizzo del target dell'evento possiamo sfruttare una medesima funzione per più oggetti, ricavando l'oggetto che ha scatenato l'evento.
Listato 3. Trascina e rilascia più pannelli
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="400">
<mx:Script>
<![CDATA[
public function trascina(evt:Event):void{
evt.target.startDrag()
evt.target.alpha = .6
var filtro:DropShadowFilter = new DropShadowFilter()
filtro.alpha = .3
filtro.distance = 30
evt.target.filters = [filtro]
}
public function lascia(evt:Event):void{
evt.target.stopDrag()
evt.target.alpha = 1
evt.target.filters = []
}
]]>
</mx:Script>
<mx:Panel x="66" y="10" width="250" height="100" layout="absolute" title="Pannello" id="pannello1" mouseDown="trascina(event)" mouseUp="lascia(event)" mouseChildren="false">
</mx:Panel>
<mx:Panel x="10" y="151" width="189" height="151.2" layout="absolute" id="pannello2" title="Pannello 2" mouseDown="trascina(event)" mouseUp="lascia(event)" mouseChildren="false">
</mx:Panel>
<mx:Panel x="217" y="151" width="173" height="200" layout="absolute" id="pannello3" title="Pannello 3" mouseDown="trascina(event)" mouseUp="lascia(event)" mouseChildren="false">
</mx:Panel>
</mx:Application>
Possiamo facilmente ottenere un effetto più gradevole portando in primo piano il pannello che viene cliccato, ciò è molto semplice grazie al comando addChild
, che permette di aggiungere un oggetto allo stage o, nel caso in cui questo oggetto sia già presente, lo sposta sulla profondità più alta disponibile. Possiamo quindi variare in questo modo la funzione trascina:
Listato 4. Porta in primo piano il pannello cliccato
public function trascina(evt:Event):void{
evt.target.startDrag()
evt.target.alpha = .6
var filtro:DropShadowFilter = new DropShadowFilter()
filtro.alpha = .3
filtro.distance = 30
evt.target.filters = [filtro]
addChild(evt.target as DisplayObject)
}
Notiamo l'uso della dicitura as DisplayObject
, che ci permette di convertire l'oggetto in un DisplayObject
, ovvero il tipo di oggetto richiesto dal comando addChild
.
Uso di più pannelli con cambio di profondità
Possiamo notare come l'ultimo pannello cliccato risulti in primo piano.
Ricordiamo che quanto visto finora è applicabile anche a elementi diversi dal componente Panel, di seguito è possibile vedere per esempio l'effetto applicato su tre diversi elementi: un componente Button, un componente Radio Button e un componente Numeric Stepper.
Uso di elementi diversi dal componente Panel
Ottenere l'effetto con Flash CS3
L'effetto visto è perfettamente replicabile anche con Flash CS3: creiamo un nuovo file Actionscript 3 (File -> New -> Actionscript 3 File) e creiamo tre clip sullo stage, dandogli nome istanza clip1, clip2, clip3. Le clip possono essere disegnate manualmente oppure essere istanze di un componente.
Portiamoci quindi nel pannello azioni e inseriamo il seguente codice:
Listato 5. Trascina e rilascia in Flash
function trascina(evt:Event):void{
evt.target.startDrag()
evt.target.alpha = .6
var filtro:DropShadowFilter = new DropShadowFilter()
filtro.alpha = .3
filtro.distance = 30
evt.target.filters = [filtro]
addChild(evt.target as DisplayObject)
}
function rilascia(evt:Event):void{
evt.target.stopDrag()
evt.target.alpha = 1
evt.target.filters = []
}
clip1.addEventListener(MouseEvent.MOUSE_DOWN,trascina)
clip1.addEventListener(MouseEvent.MOUSE_UP,rilascia)
clip2.addEventListener(MouseEvent.MOUSE_DOWN,trascina)
clip2.addEventListener(MouseEvent.MOUSE_UP,rilascia)
clip3.addEventListener(MouseEvent.MOUSE_DOWN,trascina)
clip3.addEventListener(MouseEvent.MOUSE_UP,rilascia)
Come vediamo il codice delle funzioni trascina e rilascia rimane invariato, mentre cambia il modo di associazione degli eventi alle clip che in questo caso eseguiamo tramite Actionscript.
In Flash CS3 non è presente il componente Panel, tuttavia come abbiamo detto il codice funziona su qualsiasi tipo di elemento e potremo quindi adattarlo alle nostre esigenze e ai nostri pannelli.
Esempio dell'effetto su clip disegnati in Flash