Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Famo.us, interfacce utente per app HTML5

Link copiato negli appunti

Famo.us è un framework JavaScript, gratuito e open source, nato per la creazione di interfacce utente HTML5 complesse e adatte a qualsiasi tipo di schermo. La libreria si propone di offrire il massimo dell'interattività grazie alle animazioni e alle transizioni che siamo abituati a vedere nelle applicazioni Web, nei giochi e nelle app di ultima generazione, e che funzionano su qualsiasi dispositivo.

Dal sito ufficiale è scaricare il pacchetto "starter kit" della libreria, oltre ad accedere al repository GitHub per scaricare il sorgente e contribuire al suo sviluppo.

Inoltre in allegato all'articolo si possono trovare alcuni esempi da far girare in locale, utilissimi per provare gli snippet che proporremo.

Lo "starter kit"

Il pacchetto scaricato dal sito contiene risorse aggiuntive di diverso tipo, suddivise in cartelle.

Cartella Descrizione
boilerplate contiene una pagina Web modello, script JS e CSS, che può essere copiata per ottenere una struttura di base per creare un nuovo progetto
interface-demos contiene vari demo che forniscono un esempio delle capacità della libreria e delle funzionalità che possono essere implementate nelle applicazioni
reference-* contengono la guida di riferimento dei tipi forniti dalla libreria, gli esempi di utilizzo, le domande frequenti (con le risposte) e tutorial offline approfonditi

Tutte le pagine degli esempi e lo stesso "boilerplate", importano all'interno della pagina gli script JavaScript di Famo.us e le dipendenze (come Require.js) scaricandole dalla CDN del progetto.

I componenti

Le applicazioni Famo.us possono essere realizzate creando istanze dei componenti di base della libreria, oppure "widget" riutilizzabili che assemblano al loro interno più componenti.

Per poter accedere ai tipi di qualsiasi componente, è necessario importare la relativa dipendenza tramite l'uso della libreria Require.js. Ecco un esempio di importazione degli oggetti Engine e Surface:

var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');

>> Leggi di più su Require.js

Dagli esempi di codice dell'articolo sono stati rimosse, per semplicità e brevità, le istruzioni require con i percorsi delle dipendenze, ma possono essere facilmente determinate leggendo la Reference sul sito della libreria.

Vediamo ora quali sono i componenti principali della libreria e come utilizzarli per costruire passo per passo una generica interfaccia utente.

Engine e Context

Il "motore" di Famo.us è rappresentato dall'oggetto Engine che fornisce principalmente metodi statici di utilità, tra i quali createContext() per inizializzare il contesto di esecuzione dell'applicazione, ossia un contenitore che include al proprio interno gli elementi dell'interfaccia utente, ne esegue il rendering, più in generale gestisce lo stato complessivo dell'applicazione stessa.

Il contesto è identificato da un oggetto di tipo Context e viene creato in questo modo:

// Crea il contesto principale dell'applicazione
var mainContext = Engine.createContext();

A sua volta, Context permette di aggiungere e rimuovere elementi che hanno una rappresentazione visuale all'interno dell'interfaccia.

Nota: È possibile avere più Context per una stessa applicazione, benché nella maggior parte dei casi ne verrà utilizzato solo uno.

Il componente Surface

Surface è il nome del componente più semplice, che rappresenta una "tela" sulla quale prendono posto altri elementi dell'interfaccia. Analizziamo la creazione dell'oggetto Surface nella porzione di codice che segue:

var firstSurface = new Surface({
	size: [200, 100],
	content: 'Hello Famo.us',
	properties: {
		color: 'white',
		textAlign: 'center',
		backgroundColor: '#FA5C4F'
	}
});

Il costruttore di Surface accetta un oggetto contenente proprietà che definiscono le caratteristiche della superficie da creare. I nomi di alcune proprietà ricalcano gli attributi comunemente usati nei fogli di stile, risultando quindi facilmente intuibile per lo sviluppatore o il Web designer, ma sono espressi nella cosiddetta forma "camelCase".

Per visualizzare l'oggetto Surface, dobbiamo creare un Context e aggiungervi il componente, poiché il contesto è il responsabile del rendering dei controlli presenti al suo interno:

var mainContext = Engine.createContext();
mainContext.add(firstSurface);

L'oggetto Surface viene rappresentato nel DOM come un semplice <div> a cui vengono attribuite le proprietà indicate nel costruttore. Il contenuto passato tramite la proprietà content può essere una semplice stringa di testo o un frammento di markup HTML; in alternativa, il contenuto può essere definito in un secondo momento chiamando il metodo setContent().

La vista DeviceView

Oltre ai semplici componenti di base come Surface, possiamo aggiungere al nostro contesto anche elementi più complessi, come la vista DeviceView, che permette di raffigurare un dispositivo (es. un iPad, un iPhone, un Nexus e così via) all'interno della pagina.

L'inizializzazione e la configurazione del componente avvengono sempre nel modo già esaminato in precedenza:

var device = new DeviceView({
	type: 'iphone',
	height: window.innerHeight - 200
});

Per visualizzare il controllo visuale, occorre aggiungerlo al contesto principale Context. Analogamente, la vista può svolgere a sua volta il ruolo di "contenitore" per altri componenti semplici o widget; ad esempio, supponendo di voler rappresentare un Surface all'interno della DeviceView, possiamo scrivere qualcosa di simile a questo:

// Crea il contesto principale
var mainContext = Engine.createContext(); 
// Crea il device che conterrà l'interfaccia
var device = new DeviceView(...); 
// Aggiunge il device al contesto principale
mainContext.add(device); 
// Crea la tela per l'applicazione
var firstSurface = new Surface(...); 
// Aggiunge l'oggetto al device per raffigurarlo al suo interno
device.add(firstSurface);

Esistono poi viste in grado di ospitare più di un componente al loro interno, magari visualizzandoli in un contesto specifico e non necessariamente tutti quanti allo stesso momento, oppure applicando effetti particolari.

Posizionare e dimensionare elementi

Entriamo nel dettaglio degli strumenti che Famo.us mette a disposizione per stabilire dimensioni e posizione dei componenti dell'interfaccia.

Nell'esempio di creazione dell'oggetto Surface abbiamo esplicitato le dimensioni del riquadro nella proprietà size dell'oggetto passato al costruttore; è possibile ometterle affinché il componente erediti tali dimensioni dal proprio controllo contenitore, oppure specificare solo una delle dimensioni valorizzando l'altra a true per sfruttare il meccanismo di "auto size", lasciando quindi che la dimensione si estenda in automatico fino a occupare lo spazio disponibile nel contenitore.

Per un maggiore controllo sul posizionamento e dimensionamento dei componenti, possiamo ricorrere all'uso del cosiddetto StateModifier, un oggetto che consente di definire trasformazioni, ossia traslare, riscalare, ruotare, riposizionare componenti ricorrendo alla specifica delle trasformazioni CSS3.

Ad esempio, per stabilire la posizione dell'oggetto Surface, possiamo utilizzare la classe Transform e agire in questo modo:

// Crea il contesto principale dell'applicazione
var mainContext = Engine.createContext(); 
// Crea il Modifier per alterare lo stato del contenuto,
// in questo caso traslandone la posizione
var stateModifier = new StateModifier({
	transform: Transform.translate(150, 200, 0)
}); 
// Crea la superficie da rappresentare
var surface = new Surface({
	size: [100, 100],
	properties: {
		backgroundColor: '#FA5C4F'
	}
}); 
// Inserisce il Modifier nel contesto, e la superficie nel Modifier
mainContext.add(stateModifier).add(surface);

I componenti vengono sempre posizionati in modo assoluto (con l'attributo position: absolute) e trasformati tramite CSS3, nei browser che supportano questo standard: questo è all'origine delle elevate performance offerte dalla libreria.

La possibilità di annidare componenti l'uno all'interno dell'altro, partendo dal contesto, permette di racchiudere componenti dentro altri e concatenare più trasformazioni. Ad esempio, per traslare e ruotare una superficie, è possibile procedere in questo modo:

// Crea il contesto principale dell'applicazione
var mainContext = Engine.createContext(); 
// Crea il Modifier per traslare i contenuti
var traslateModifier = new StateModifier({
	transform: Transform.translate(150, 200, 0)
}); 
// Crea il Modifier per ruotare i contenuti
var rotateModifier = new StateModifier({
	transform: Transform.rotateZ(Math.PI/4)
}); 
// Crea la superficie da rappresentare
var surface = new Surface({
	size: [100, 100],
	properties: {
		backgroundColor: '#FA5C4F'
	}
}); 
// Combina i componenti nel contesto
mainContext
.add(translateModifier)
.add(rotateModifier)
.add(surface);

Nota: Poiché le trasformazioni modificano il sistema di riferimento, occorre prestare attenzione all'ordine con cui vengono applicate ai componenti.

Per posizionare e allineare componenti in modo più semplice, è possibile istanziare l'oggetto StateModifier con le proprietà align e origin, che possono essere specificate in combinazione con l'uso di transform; infine, è possibile modificare la trasparenza del contenuto tramite la proprietà opacity:

var modifier = new StateModifier({
	opacity: 0.5,
	transform: Transform.scale(1, 3, 1),
	align: [0.5, 0.5],
	origin: [0.5, 0.5]
});

Nella seconda parte dell'articolo vediamo come creare animazioni e sfruttare al meglio le trasformazioni.

Creare animazioni

Abbiamo visto come utilizzare l'oggetto StateModifier per trasformare lo stato iniziale di un componente. Utilizzando il metodo setTransform(), possiamo modificare tale stato in un secondo momento, con la possibilità di applicare un'animazione nel passaggio dallo stato iniziale a quello desiderato.

È possibile eseguire più chiamate a setTransform() per definire trasformazioni da applicare in sequenza, definendone la durata dell'animazione di ciascuna, l'effetto da applicare (easing curve) e una callback facoltativa per intercettare il momento in cui l'animazione, eseguita in modo asincrona, termina il proprio lavoro.

Nota: Famo.us supporta più di 30 curve e svariate transizioni realistiche!

stateModifier.setTransform(
	Transform.translate(0, 300, 0),
	{ duration : 1000, curve: Easing.inExpo }
); 
stateModifier.setTransform(
	Transform.translate(100, 300, 0),
	{ duration : 800, curve: Easing.outElastic },
	function() {
		surface.setContent('finished');
	}
);

È possibile interrompere un'animazione in corso chiamando il metodo halt() sull'oggetto StateModifier.

Gestione degli eventi

Famo.us include una gestione degli eventi che consente di intercettare le possibili interazioni dell'utente sui controlli dell'interfaccia ed eseguire codice arbitrario in risposta.

Possiamo intercettare gli eventi supportati tipicamente dal DOM, per i quali definiamo un callback usando il metodo on(), a cui viene passato il nome dell'evento e la funzione di callback da eseguire.

Per gestire ad esempio il clic con il mouse (o il tocco con il dito su dispositivi che offrono questa possibilità) su una generica Surface, possiamo scrivere

mySurface.on("click", function () {
	alert("Ouch!");
});

La scrittura ricorderà a molti sviluppatori il "binding" degli eventi di JQuery: l'uso di un costrutto simile facilita l'adozione della libreria, smussa la curva di apprendimento, permette di essere subito produttivi e agevola la migrazione di codice JavaScript eventualmente esistente basato su JQuery.

Questi sono gli eventi Surface supportati dalla libreria:

Eventi Mouse Eventi Touch Eventi Tastiera
click touchstart keydown
mousedown touchmove keyup
mousemove touchend keypress
mouseup touchcancel
mouseover
mouseout

È possibile intercettare gli eventi "globalmente" all'interno dell'applicazione chiamando il metodo on() direttamente sulla classe Engine, che offre una gamma più estesa di eventi:

Engine.on('resize', function() {
	surface.setContent('resized');
});

Gli eventi costituiscono inoltre un meccanismo efficiente per consentire ai diversi componenti dell'applicazione di comunicare tra loro attraverso un oggetto EventHandler. Vediamolo nel codice:

// Crea un riquadro di esempio
var surface = new Surface(); 
// Crea il gestore degli eventi
var eventHandler = new EventHandler(); 
// Quando si fa click sul riquadro, genera l'evento personalizzato "hello"
surface.on('click', function() {
	eventHandler.emit('hello');
}); 
// Qui si intercetta l'evento personalizzato modificando il contenuto del riquadro
eventHandler.on('hello', function() {
	surface.setContent('heard hello');
});

Per intercettare l'evento si utilizza sempre il metodo on(), mentre il metodo emit() consente di scatenarlo.

È possibile collegare un EventHandler a un altro tramite il metodo subscribe() per intercettare dal primo gli eventi scatenati tramite il secondo.

Conclusioni

Famo.us contiene numerosi componenti per costruire interfacce complesse: contenitori per organizzare i componenti in base a diverse tipologie di layout, widget per la navigazione a schede o con barre, surface avanzate per la visualizzazione di immagini e video, controlli di input, viste per slideshow, funzioni matematiche e altro ancora. Ciascuno dei componenti avanzati offre eventi, contenitori per il posizionamento dei controlli e proprietà specifici per un controllo completo.

Sul sito ufficiale è possibile approfondire tutte le risorse messe a disposizione dalla libreria, imparare ad utilizzarla efficacemente seguendo le lezioni della Famo.us University ed esaminare interessanti demo di applicazioni complete nella galleria.

Ti consigliamo anche