lunes, 26 de enero de 2015

Animación estilo metro con Titanium

En ocasiones he necesitado indicar al usuario de la aplicación móvil que un proceso necesita cierto tiempo para realizarse, como la conexión a un servidor para enviar o recoger datos, o sencillamente actualizar la posición GPS.
A menudo, siguiendo las tendencias actuales, esta información se requiere de una forma limpia y no intrusiva.
Siguiendo estos parámetros he creado una utilidad que realiza una animación sobre el borde superior de una vista, utilizando un gradiente en el color de fondo (backgroundColorGradient).

La función animateGradient está incluida dentro del módulo utils.js, por tanto para usarla haremos algo así:

var utils = require('/utils');
var activity = utils.animateGradient(view,options);
// una vez terminada la actividad invocaremos
activity.destroy();


view es un contenedor de tipo Titanium.UI.createView y options puede albegar de momento las opciones que indican la velocidad de animación y los colores.

Veamos como está hecho.


animateGradient: function (view, options)
{
// in android isn't possible to include a view inside an object that is not a view
if((Titanium.Platform.osname == "android") && (view.toString() !== '[object View]')){
alert('Error on type calling animateGradient, called with '+view.toString());
setTimeout(function(){
Titanium.Android.currentActivity.finish();
},2500);
return;
}

...
}


Lo primero es comprobar que se ha llamado con el tipo de parámetro adecuado, pues en android no se puede usar un contenedor que no sea un objeto de tipo Titanium.UI.createView, en iOS he probado con un button directamente y funciona bien.


animateGradient: function (view, options)
{
// check if view parameter is right in android platform ...
if(typeof(options) === "undefined"){
options = {};
}
var timeout = options.timeout || 75;
var colors = options.colors || ['#0000aa', '#000099'];

...
}


Ahora se establecen las opciones por defecto para el caso de no indicarlas, luego explicaré para que hacen falta dos colores.


animateGradient: function (view, options)
{
// check if view parameter is right in android platform ...
// establish default options and set it to local variables ...
/**
* the view that host the activity bar
*/
var linearGradient = Titanium.UI.createView({
top: 0,
left: 0,
width: '100%',
height: '3dp',
zIndex: 1000
};
view.add(linearGradient);

...
}


Lo primero es crear una vista que va a albergar nuestra animación, como puedes ver estará en el borde superior, con ancho total y una altura de 3dp, el valor de zIndex es como medida de precaución para que sea visible en cualquier caso.


animateGradient: function (view, options)
{
// check if view parameter is right in android platform ...
// establish default options and set it to local variables ...
// create animation view container inside the main view ...
var gradient = {
inc: 0.02,
x: 0.05,
colorIndex: 0,
colors: colors,
baseColor: view.backgroundColor,
color: function(){
this.colorIndex = (this.colorIndex+1)%2;
return this.colors[this.colorIndex];
}
};

...
}


Creamos un objeto auxiliar para encapsular toda las variables que necesitamos. Fíjate como el color de fondo es exactamente el mismo que la vista principal.


animateGradient: function (view, options)
{
// check if view parameter is right in android platform ...
// establish default options and set it to local variables ...
// create animation view container inside the main view ...
// auxiliary object in order to encapsulate all variables ...
/**
* timer that simulates the activity though changing gradient color
*/
var interval = setInterval(function(){
if((gradient.x > 0.95) || (gradient.x<0.05)){
gradient.inc = -gradient.inc;
}
gradient.x += gradient.inc;
linearGradient.backgroundGradient = {
type: 'linear',
startPoint: { x: '0%', y: '50%' },
endPoint: { x: '100%', y: '50%' },
colors: [
{ color: gradient.baseColor, offset: 0.0},
{ color: gradient.baseColor, offset: gradient.x-0.05},
{ color: gradient.color(), offset: gradient.x },
{ color: gradient.baseColor, offset: gradient.x+0.05 },
{ color: gradient.baseColor, offset: 1.0 }
]
};
}, timeout);

...
}


Ahora viene la parte que realmente hace la animación, un intervalo que en cada iteración crea la ilusión de que el gradiente del color de fondo se mueve. Para forzar a Titanium a que pinte la vista de nuevo hay que indicar cada vez un color diferente, por eso se utilizan dos colores, para que el efecto sea más bonito y auténtico no deben distar mucho ambos colores, fíjate en los que se usan por defecto.


animateGradient: function (view, options)
{
// check if view parameter is right in android platform ...
// establish default options and set it to local variables ...
// create animation view container inside the main view ...
// auxiliary object in order to encapsulate all variables ...
// timer that simulates the activity though changing gradient color ...
return {
linearGradient: linearGradient,
view: view,
destroy: function(){
clearInterval(this.interval);
view.remove(linearGradient);
},
interval: interval
};
}


Al final se devuelve un objeto con los datos necesarios, el más importante es la función que nos va a permitir deshacernos de la vista temporal usada para crear la animación.



El código fuente completo de la animación incluido en una pequeña aplicación de ejemplo lo tienes a tu disposición en mi cuenta de github.

Vamos a ver el ejemplo de uso completo:


...
var testBtnView = Titanium.UI.createView({
backgroundColor: "#aaa",
top: "50%",
height: '50dp',
width: "225dp"
});
win.add(testBtnView);

var testBtn = Titanium.UI.createButton({
color: 'white',
backgroundColor: '#aaa',
title: "TEST",
font: {fontSize:'18dp',fontFamily:'Helvetica Neue',fontWeight:'bold'},
textAlign: 'center'
});
testBtnView.add(testBtn);
...
function testBtnHandler(){
console.info("test button clicked");
activity = utils.animateGradient(testBtnView);
// simulate an action that lasts 5 seconds
setTimeout(function(){
activity.destroy();
}, 5000);
}
...


Espero vuestros comentarios.

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.