Las vistas de aplicaciones nativas (iOS, Android) tienen un ciclo de vida bien estructurado que permite realizar acciones en momentos clave de su ejecución. Ionic 2 cuenta con una característica equivalente: Los lifecycle events de navegación.
En Ionic 2, cualquier vista que se añade o quita a un NavController
emite ciertos eventos que puedes aprovechar para inicializar la vista, refrescar contenido o guardar datos, por ejemplo.
Enseguida descubrirás como usarlos gracias a un ejemplo hands-on code, pero primero… ¡vamos a profundizar en el tema!
Lifecycle events
Los eventos de navegación de Ionic 2 son muy similares a los que define iOS. Aquí tienes un diagrama que muestra como funcionan.
Resumiendo, los eventos son estos:
ionViewDidLoad
: Se llama únicamente cuando cargas una página en memoria (push). Este evento NO se lanza si entras por segunda vez en una vista que ya está cacheada. Es un buen sitio para tareas relacionadas con la inicialización de la vista.-
ionViewWillEnter
: Se ejecuta cuando entras en una página, antes de cargarla. Utilízalo para tareas que se deben realizar siempre que entras en la vista, exista ya o no (activar listeners de eventos, actualizar una tabla, etc). -
ionViewDidEnter
: Se ejecuta cuando entras en una página, después de cargarla. Ahora ésta es la página activa. Muy similar a la anterior. -
ionViewWillLeave
: Se ejecuta cuando sales de una página, justo antes de salir. Utilízalo para esa lógica que necesitas siempre que sales de la vista (desactivar listeners, etc). -
ionViewDidLeave
: Se ejecuta cuando sales de una página, al acabar de salir. Ahora ésta ya no es la página activa. Muy similar a la anterior. -
ionViewWillUnload
: Se ejecuta cuando vas a destruir por completo una página (al hacer pop).
Nav guards
Como bonus track hay 2 métodos muy potentes relacionados con estos eventos, que te facilitan el control de acceso a vistas que necesitan autenticación (por ejemplo).
ionViewCanEnter
: Se ejecuta antes de entrar en una vista y te permite controlar si realmente puedes entrar en la vista o no (devolviendo true o false).-
ionViewCanLeave
: Se ejecuta antes de salir de una vista y te permite controlar si realmente puedes salir de la vista o no.
Es importante destacar que los Nav Guards se ejecutan los primeros, antes que cualquier función del lifecycle event.
Hands-on code!
Reproductor de musica ambiental
Todo se entiende mejor al ponerlo en práctica, así que te traigo un ejemplo divertido: Un reproductor de música ambiental.
Puedes bajarte el proyecto desde el siguiente enlace:
Es un ejemplo muy simple donde hay una app con 3 vistas:
- La vista Home permite escoger un ambiente sonoro
- La vista Music reproduce audio ligado a ese ambiente. Ya te avanzo que aquí es donde necesitarás usar los lifecycle events.
- La vista Credits, a la que se accede desde Music, muestra información de la app
Es decir, el flujo de navegación de las vistas es el siguiente:
La vista Music reproducirá música según el ambiente seleccionado. La reproducción de música corre a cargo de howler.js.
Vista Home
La vista principal es muy simple: Muestra una lista de botones para acceder a los distintos ambientes, con una imagen de fondo y un texto. Todo esto aderezado con un poquito de SaSS para ponerlo bonito.
El template de esta vista no tiene nada especial, solo destacar que para pasar a cada ambiente se llama al método goToMusicPage()
del propio componente, pasando como argumento el nombre del ambiente.
home.html
<ion-header>
<ion-navbar>
<ion-title>Relax yourself v0.1</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<div class="imageBtn" (click)="goToMusicPage('ocean-waves')">
<div class="image" style="background-image:url('assets/img/ocean-waves.jpg');"></div>
<div class="label">Ocean Waves</div>
</div>
<!-- ...some more DIVs like this ...-->
</ion-content>
Puedes ver la navegación que hace goToMusicPage
en el código del componente:
home.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { MusicPage } from '../music/music';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController) {}
goToMusicPage(audio){
this.navCtrl.push(MusicPage, {audio});
}
}
Vista Music
La vista Music es aún más simple. Solo muestra una imagen relacionada con el ambiente y un botón en el header para ir a la vista Credits.
Eso sí, en esta vista oyes música.
Lo único destacable del template de Music es la navegación a Credits con la directiva navPush
.
music.html
<ion-header>
<ion-navbar>
<ion-title>Playing...</ion-title>
<ion-buttons end>
<button ion-button icon-only [navPush]="creditsPage">
<ion-icon name="information-circle"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<div [style.backgroundImage]="'url(' + image +')'"></div>
</ion-content>
Si no reprodujera audio, el componente Music sería muy simple:
music.ts
import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { CreditsPage } from '../credits/credits';
import * as howler from 'howler';
@Component({
selector: 'page-music',
templateUrl: 'music.html'
})
export class MusicPage {
music:any;
image:string;
creditsPage:any;
constructor(public navCtrl: NavController, public params: NavParams) {
this.creditsPage = CreditsPage;
}
/* lifecycle events */
//TODO: add lifecycle events to load, play, pause and stop audio
/* end lifecycle events */
}
Pero como ves, necesito usar los eventos de lifecycle para gestionar la carga y reproducción del audio.
ionViewDidLoad
Cuando cargo un ambiente musical (push), necesito meter en memoria el audio correspondiente, pero sin hacerlo varias veces. Por eso utilizo ionViewDidLoad
.
Como ves recibo el nombre del ambiente por parámetro y lo uso para obtener la imagen de fondo y cargar el audio correspondiente.
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {
let audioFile = this.params.get('audio');
this.music = new howler.Howl({ src: [`assets/music/${audioFile}.mp3`]});
this.image = `assets/img/${audioFile}.jpg`;
}
//TODO: add lifecycle events to play, pause and stop audio
/* end lifecycle events */
}
ionViewWillEnter
Cada vez que Music
pasa a ser la vista activa hay que reproducir su audio ambiente. Esto lo hago en ionViewWillEnter
porque si lo hiciera en el evento anterior, no se ejecutaría al volver de la vista Credits.
Nota: ionViewWillLeave
también serviría)
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {/*...*/}
ionViewWillEnter(){
this.music.play();
this.music.loop(true);
}
//TODO: add lifecycle events to pause and stop audio
/* end lifecycle events */
}
ionViewDidLeave
Cada vez que Music
deja de ser la vista activa hay que pausar su audio ambiente. Uso ionViewDidLeave
para que funcione también al navegar a Credits.
Nota: ionViewWillLeave
también serviría.
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {/*...*/}
ionViewWillEnter() {/*...*/}
ionViewDidLeave(){
this.music.pause();
}
//TODO: add lifecycle events to stop audio
/* end lifecycle events */
}
ionViewWillUnload
Finalmente, quiero asegurarme de que al volver a Home, antes de destruir la vista Music he parado la música. Para eso utilizo ionViewWillUnload
.
export class MusicPage {
/* ...some stuff ...*/
/* lifecycle events */
ionViewDidLoad() {/*...*/}
ionViewWillEnter() {/*...*/}
ionViewDidLeave() {/*...*/}
ionViewWillUnload() {
this.music.stop();
this.music = null;
}
/* end lifecycle events */
}
Vista Credits
La vista Credits es solo una excusa para mostrarte la utilidad de los eventos anteriores. Es tan simple que no te enseño ni el código, con una captura bastará 😉
Resultados
Aquí tienes un vídeo con el resultado. Acuérdate de subir el sonido, sino no tiene gracia 😉
Si tienes alguna duda o comentario, házmelo saber aquí abajo 😉
Hola Enrique,
Viene de perlas. Aunque cuando explicas algo, todo parece facil, happy & water-flowing.. pero cuando uno se pone… eso es otra cosa, y para mi está siendo una cruz, un paso para adelante y dos para atrás.. ;-p
Sería genial un bonus track 2, con la navegación por tabs y cuando usar viewChild (que no me aclaro) y la diferencia entre Nav y NavController ,y… Como usar servicios en un modal ¿se puede? y… (lo se, solo hago que pedir .. .. )
merci !
Tomo nota 😉
¿Qué cosas te han presentado dificultades de este tutorial en concreto?
¡Un abrazo!
Hola!
Tengo una consulta. Me bajé el proyecto, le di npm install, luego ionic serve, todo funciono bien en el navegador de escritorio. Queria probarlo en el movil, así que le di ionic upload para verlo con ionic view, y veo unos problemas:
1. La música se escucha entrecortada
2. Cuando vuelves al home se sigue escuchando.
Es un problema puntual mío? o alguien también le pasa.
Gracias!!
Yo lo he ejecutado en dispositivo Android sin problemas.
¿Has probado a debugar para ver por qué no se para al volver a home? Lo de la música entrecortada podría deberse al dispositivo. ¿Qué móvil es?
Saludos
Lo has ejecutado con ionic view? voy a debugar para ver si encuentro algo. Es un samsung galaxy alpha android 4.4.4
No, yo ejecuto directamente sobre el dispositivo, asi te evitas pelear con problemas que pueden no venir de tu código.
un video tutorial de esto no seria mala idea 😀 se entiende todo mejor cuando lo explicas paso por paso
Excelente explicación! , tengo una duda es posible comunicar aplicaciones entre si con Ionic 2 ? Es decir pasar un valor cualquiera de una aplicación «A» a otra aplicación aparte «B» , es posible
Pues así como así no, pero puedes hacer que las dos apps se comuniquen con el mismo servidor o lanzar una app desde la otra a través de URLScheme y aprovechar para pasarle información.
Gracias por la respuesta! logre hacerlo con URLScheme.
Hola Enrique!
Muy bueno y sencillo el tutorial, solo quisiera hacerte una pregunta.
Que diferencia hay entre usar Howler.js y el audio nativo de HTML5? Por lo que veo, los metodos de estos son bastantes parecidos (audio.play() , audio.pause(), etc)
Pregunto porque primero se me ocurrio hacerlo con html5, lo hice y funcionó. Pero despues quise investigar un poco a ver si habia alguna manera «mejor» de hacerlo.
Por ejemplo, al bloquear pantalla, usando el reproductor de html5, se para el audio. Y en moviles esto es algo basico que no tiene que pasar para una app musical.
Saludos!
Howler.JS utiliza la Web Audio API y en caso de incompatibilidad, acaba usando la API de audio de HTML5. Si te paras a mirar lo que se puede hacer con Howler.JS, verás que es mucho más potente que la API de audio de HTML5.
En todo caso, para un ejemplo tan simple como este, he elegido HowlerJS por una cuestión de gustos: No me gusta que el audio vaya metido en una etiqueta HTML, así de fácil 😉
Perfecto, es Io que necesitaba saber. Una ultima pregunta… para incluir Howler.JS en el proyecto, como hago?
Para instalarlo, desde terminal:
npm install howler
Y donde lo quieras usar lo importas con sintaxis ES6:
import * as howler from 'howler';
Si tienes dudas puedes mirar el código del repo: https://github.com/kaikcreator/ionic2LifeCycleExample
Genial, muchísimas gracias! También me sirvió mucho el post de celery + django.
Un saludo y gracias por compartir estas cosas!
Me alegro de que te sirva 😉
¡Saludos!
Se puede hacer lo mismo pero en ves de audio sea videos?
Si claro, ¿por qué no?
Hola, me parece muy buento tu post y te lo agradezco por que es de mucha ayuda, pero una consulta. Al compilar me arroja un error linea de let audioFile = this.params.get(‘audio’);. El error dice: No platforms add.Please use cordova platform add
Ese error básicamente te indica que tienes que añadir una plataforma cordova (android o ios). Eso será por que estás haciendo un `build` o un `run` y claro, necesitas tener los archivos de cordova instalados para crear la app.
Intenté creando uno nuevo o utilizando lo que dejaste en el repositorio, pero no me funciona. No me carga las imágenes, tampoco se escucha los audios =(. Lo compilé y probé en mi móvil.
No sé si sea por las versiones o algo. Ayuda por favor.
Hola, gracias por compartir.
Podrias hacer un tutorial explicando como cargar las canciones del almacenamiento del movil con ionic 3
Cuando uso un proyecto con SideMenu cada que navego entre las distintas pagina se me llama todo lo que está en ionViewDidLoad de la pagina funcionando como si fuera un ionViewDidEnter.
Como puedo solucionarlo?
Hola Enrique Oriol, gracias por este tutorial y por todo tu aporte que haces a la comunidad, tengo una consulta. estoy realizando una aplicación en donde quiero reproducir audio streaming, veo que ionic tiene un plugin de Streaming Media pero al momento de pasar a otra vista o el telefono se bloquea la aplicacion deja de sonar.
howler permite trabajar audio streaming? y ademas permite trabajar en background mode?
podrias tal vez hacer una actualizacion de este temas abordando el punto de audio streaming y el trabajo en backgroun mode?
Hola Enrique , esta muy buena la aplicación , pero te agrego algo que me pidieron y es, como hago para agregar un boton que reproduzca la secuencia de sonidos en en el orden en que yo apreté los botones?
Hola Enrique , quería saber como hacer para a este ejemplo agregarle un botón para que reproduzca la secuencia en la que presiono los botones, estuve intentándolo y no me sale, me podrías ayudar
Hola soy nuevo en ionic 3 como hago para poner una funcion dentro de un evento es posible?
muchas gracias por la explicación la cual esta clarísima !!
Hola Enrique gracias por el tutorial muy practico,
yo utilizo ionic 3 queria preguntarte si los eventos son los mismos en ionic 3?
si utilizo plugins nativos el platform.ready() esta dentro los eventos por ejemplo ionViewWillEnter? o tengo que hacerlo a mano en cada uno ?
y si es el segundo caso el platform.ready() tengo que hacerlo en cada pagina o solo en el app.component?
graciasss
Resulta que cuando ingreso a la página me trae un listado grande de items que luego renderizo en la página, pero antes de renderizar muestro un loading…
El problema es que no encuentro un evento que se dispare una vez termine todo de rederizar, para proceder a cerrar el loading. Pues el loading se está cerrando antes de renderizar el contenido de la página.
Cual sería dicho evento o cómo lo puedo hacer?