Aitor Sánchez - Blog - Oct. 26, 2023, 11:15 a.m.
¿Quieres hacer un step by step, o montar un carrousel de imágenes en tu app? O, tal vez, solo buscas información de alguno de los campos o funciones de Ionic Slider ¿verdad?
Mi nombre es Aitor Sánchez, soy desarrollador de apps desde 2014, y en artículo de hoy te enseñaré cómo montar una interfaz más interactiva, versátil y atractiva gracias a la implementación de un slider dentro de tu aplicación.
Pero antes de continuar, esta es la Flutter Mafia. Es mi newsletter donde aprenderás desarrollo de apps móviles, aso y monetización junto con otros genietes que ya están dentro. Y si te suscribes te regalo mi ebook "Duplica los ingreso de tus apps en 5 minutos" No es broma, quizás te interese.
Nota: La diferencia que encontraremos entre los "slide ionic ios" y "ionic slide android" de manera programática será nula. Pero sí que hay un poco de diferencia visual. Sobre todo, en los paginadores que veremos más adelante.
Vale, si ya conoces este tipo de componentes y lo que te interesa es profundizar un poco más sáltate este punto.
Son los típicos carruseles de imágenes que vemos en muchas webs a día de hoy (aunque cada vez menos) llevados un poco más allá.
Digamos puedes construir controles y componentes que pueden ser deslizados de manera horizontal, o vertical, mostrándonos solo de uno, o los que elijamos, en pantalla. A parte de eso cuentan con efectos, tamaños, y más cosas que vamos a ver a continuación.
Continuamos avanzando y ahora vamos a ver cómo puedes construir tu Slider propio. Este componente tiene una amplia gama de personalización así que tendrás entretenimiento para rato.
En primer lugar, vas a ver los dos componentes principales que vas a utilizar para construirlo.
Uno de ellos es "ion-slides" y el otro "ion-slide".
El primero será el que crea la estructura por debajo y el segundo es el control padre donde construiremos todo nuestro código html. Decir también que el ion-slide tiene que ir dentro de ion-slides. De no ser así la vista de tu app puede ser impredecible.
<ion-slides>
<ion-slide>
<h1>Slide 1</h1>
</ion-slide>
<ion-slide>
<h1>Slide 2</h1>
</ion-slide>
<ion-slide>
<h1>Slide 3</h1>
</ion-slide>
</ion-slides>
Cómo ves en el código, es simplemente lo que he explicado en la parte de encima de este. Algo que, de momento, es sencillo ¿verdad?
Aquí tienes un poco más de código, ahora le toca a TypeScript.
import { ViewChild } from '@angular/core';
import { Slides } from 'ionic-angular';
class MyPage {
@ViewChild(Slides) slides: Slides;
goToSlide() {
this.slides.slideTo(2, 500);
}
}
Ya tienes la referencia de tu Slider almacenada en la variable Slides. Ahora es plan de ponerse a jugar con él.
Como has podido comprobar, para poner un ejemplo, he decidido insertar en el código un método que, aunque seguro ya lo sabes, lleva la posición de tu Slider a la 2 con un tiempo de "recorrido" (vamos a llamarlo así) de 500 milisegundos.
ASí, que te valga de ejemplo para ver más cosas.
Genial, seguro que ya comprendes un poco más cómo funciona. Ahora vas a darle la puntilla para que sepas 100% como rula.
Sí, como has leído en el tercer punto, puedes hacer lo que quieras con él. Puedes meter imágenes / image, vídeos, texto, párrafos, ion-items, checkbox, inputs, buttons, bars, lo que quieras.... pero una cosa más hay que agregar. ¡PUEDES METER TODO JUNTO!
Espera Aitor, espera. ¿Que qué? Si, has escuchado bien, puedes incluir todos los componentes que quieras, separados o en conjunto, dentro de nuestro ion-slide. ¿Cómo te quedas? Aquí tienes un ejemplo:
<ion-slides>
<ion-slide *ngFor='let item of miArray'>
<ion-card>
<ion-card-header>
<img src='{{item.imagen_destacada}}'>
</ion-card-header>
<ion-card-content>
<h2>{{item.nombre}}</h2>
{{item.extracto}}
</ion-card-content>
</ion-card>
<ion-slide>
</ion-slides>
Pongamos la situación de que tienes un array de usuarios, donde lo que quieres mostrar es una tarjeta con los datos de cada uno metidos en un carrusel / carousel. Pues bien, este código puede servirte perfectamente.
En el *ngFor, recorres todos los espacios de memoria del array. Y luego, simplemente, llamando al "item" puedes extraer los datos de cada uno. Aunque esto, si sigues este blog, ya lo sabrás.
Me gustaría mucho que hicieras una mini app que disponga de un código así, verás que alucinante es, y me lo cuentes. Mientras tanto, continuemos.
En primer lugar, y dentro del componente que contenga el Slider en cuestión, necesitas escribir el siguiente código:
...
@ViewChild('mySlider') slides: IonSlides;
....
swipeNext(){
this.slides.slideNext();
}
...
Cómo intuirás, la primera línea "@ViewChild" te dará una referencia al componente que estamos usando en el html. Y la función "swipeNext" es la que, en si misma, te permite avanzar una posición en dicha referencia.
El código html sería el siguiente:
<ion-slides pager="true" pager="false" #mySlider>
<ion-slide>
</ion-slide>
<ion-slide>
</ion-slide>
<ion-button (click)="swipeNext()">Next</ion-button>
</ion-slides>
Una implementación muy sencilla que ahora podrás usar en tus aplicaciones porque es 100% funcional :) Sigamos...
Como todo componente, o como la mayoría, tiene sus propios eventos. Como digo siempre, no comentaré todos, porque son muchos, y solo lo que tienen que ver con el componente en cuestión.
Me ha parecido interesante colocar este aquí por una razón. En las nuevas entregas de Ionic cada vez más se está tendiendo a suplantar a Angular como Framework para desarrollar WebsApps. Quizás muchos no lo compartís, otros sí, pero yo en este caso me alegro. Así solo tengo que acostumbrarme a uno...
En fin, esta función lo que nos permite es permitir que el Slider cambie de posición cuando hacemos uso de las flechas de dirección del teclado.
Nos devuelve la posición actual en la que está nuestro Slider. Es una función sencilla para identificar, por ejemplo, el objeto que se ha pulsado para tratarlo de cualquier forma.
Un ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para obtener el índice del slide activo
obtenerIndiceActivo(): void {
this.slides.getActiveIndex().then(indice => {
console.log(`Índice del slide activo: ${indice}`);
});
}
}
Interesante esta función dirás. ¿Para qué la queremos si tenemos el índice actual? Pues muy sencillo, es para cuando el Slider está moviéndose. Porque hasta que no termine el recorrido que está llevando, "activeIndex" siempre será uno menos.
Veamos un ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para obtener el índice del slide anterior
obtenerIndiceAnterior(): void {
this.slides.getPreviousIndex().then(indiceAnterior => {
console.log(`Índice del slide anterior: ${indiceAnterior}`);
});
}
}
Nos devuelve un booleano que nos dice si el Slide está en la primera posición o no.
Un ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para verificar si el slide actual es el primero
verificarSiEsPrimerSlide(): void {
this.slides.isBeginning().then(esPrimerSlide => {
if (esPrimerSlide) {
console.log('El slide actual es el primero.');
} else {
console.log('El slide actual no es el primero.');
}
});
}
}
Similar al anterior, pero que nos devuelve si está en la última posición del Slider.
Un ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para verificar si el slide actual es el último
verificarSiEsUltimoSlide(): void {
this.slides.isEnd().then(esUltimoSlide => {
if (esUltimoSlide) {
console.log('El slide actual es el último.');
} else {
console.log('El slide actual no es el último.');
}
});
}
}
Como toda función length, nos devuelve la cantidad de Slides que componen el Componente.
Nos permite hacer que el usuario no pueda continuar al siguiente Slide dependiendo de lo que pasemos por parámetro. Se puede llamar en tiempo de ejecución para bloquear y desbloquear el Slider dependiendo, por ejemplo, del paso del registro en el que se encuentre el usuario.
Un ejemplo práctico
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para bloquear o desbloquear el deslizamiento hacia el siguiente slide
bloquearDeslizamientoASiguiente(bloquear: boolean): void {
this.slides.lockSwipeToNext(bloquear).then(() => {
console.log(`Deslizamiento hacia el siguiente slide ${bloquear ? 'bloqueado' : 'desbloqueado'}`);
});
}
}
Similar al anterior, pero para el Slider anterior y no el siguiente.
Ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para bloquear o desbloquear el deslizamiento hacia el slide anterior
bloquearDeslizamientoAAnterior(bloquear: boolean): void {
this.slides.lockSwipeToPrev(bloquear).then(() => {
console.log(`Deslizamiento hacia el slide anterior ${bloquear ? 'bloqueado' : 'desbloqueado'}`);
});
}
}
Similar a los dos anteriores, pero para o tener que llamar a las dos funciones. Así si llamamos a esta se bloqueará, o desbloqueará, para el anterior y el siguiente.
Ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para bloquear o desbloquear el deslizamiento en ambos sentidos
bloquearDeslizamientos(bloquear: boolean): void {
this.slides.lockSwipes(bloquear).then(() => {
console.log(`Deslizamientos ${bloquear ? 'bloqueados' : 'desbloqueados'}`);
});
}
}
Bien, aquí tenemos a una de las funciones que más usaremos en nuestras apps cuando usemos este componente. Como su propio nombre indica, avanza el módulo a la posición siguiente y recibe por parámetros, en primer lugar, la velocidad en milisegundos que quieres que tarde en llegar y una función callback que nos permite controlar cuando el slider ha llegado al final.
Ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para moverse al siguiente slide con parámetros opcionales
avanzarAlSiguienteSlide(velocidad?: number, ejecutarCallbacks?: boolean): void {
this.slides.slideNext(velocidad, ejecutarCallbacks).then(() => {
console.log('Se ha movido al siguiente slide');
});
}
}
El similar a la función anterior, pero en lugar de avanzar, retrocede.
Ejemplo
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para moverse al slide anterior con parámetros opcionales
regresarAlSlideAnterior(velocidad?: number, ejecutarCallbacks?: boolean): void {
this.slides.slidePrev(velocidad, ejecutarCallbacks).then(() => {
console.log('Se ha movido al slide anterior');
});
}
}
Función que es similar a las dos anteriores, pero en lugar de ir hacia delante, o hacia atrás, nos permite decirle a que posición del índice queremos que nos lleve el Slider. Se lo pasamos como primer parámetro y listo. Hay que tener cuidado si rellenamos el array de manera dinámica para no pasarnos del índice. De lo contrario lanzará un error.
Ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para moverse a un slide específico con parámetros opcionales
moverAlSlide(indice: number, velocidad?: number, ejecutarCallbacks?: boolean): void {
this.slides.slideTo(indice, velocidad, ejecutarCallbacks).then(() => {
console.log(`Se ha movido al slide con índice: ${indice}`);
});
}
}
Nos permite poner en piloto automático la reproducción del movimiento del Slider. Comúnmente llamado autoplay.
Ejemplo
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para iniciar la reproducción automática de los slides
iniciarAutoplay(): void {
this.slides.startAutoplay().then(() => {
console.log('La reproducción automática ha comenzado');
});
}
}
Lo contrario que la función anterior.
Ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para detener la reproducción automática de los slides
detenerAutoplay(): void {
this.slides.stopAutoplay().then(() => {
console.log('La reproducción automática ha sido detenida');
});
}
}
Este método nos permite actualizar el contenido de nuestros componentes. En caso de que actualicemos el contenido de los arrays que se recorren cuando construimos el html, tendremos que llamar a esta función para actualizarlos.
Ejemplo:
import { Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'mi-componente',
templateUrl: 'mi-componente.html',
styleUrls: ['mi-componente.scss'],
})
export class MiComponente {
@ViewChild(IonSlides, { static: false }) slides: IonSlides;
constructor() {}
// Función para actualizar el slider
actualizarSlider(): void {
this.slides.update().then(() => {
console.log('El slider ha sido actualizado');
});
}
}
Bien, pues estas son las funciones que iremos usando normalmente. Como he dicho al principio no voy a comentar todas ni las de los padres. Así que estas que hemos visto son las que más importantes me han parecido y seguramente las que más vamos a usar.
Ahora vamos a ver las propiedades de este componente. Como también he comentado al principio del artículo, no son pocas. Así que esto se extenderá un poquito.
Las propiedades que vamos a ver aquí, como su propio nombre indica, son campos / fields que son públicos y pueden ser asignados directamente asignando el valor sin necesidad de pasar por una función get o set. También recordar que cogerá el height automático del alto de los componentes que contenga. Si queréis modificarlo, tendréis que modificar el alto de estos.
<ion-slides autoplay="2000"></ion-slides>
"<ion-slides centeredSlides="true"></ion-slides>
"<ion-slides direction="horizontal">
<ion-slides direction="vertical">
<ion-slides effect="fade">
<ion-slides effect="cube">
<ion-slides effect="coverflow">
<ion-slides initialSlide="2">
"<ion-slides loop="true">
"<ion-slides pager="true">
"<ion-slides pager="true" paginationType="bullets">
<ion-slides pager="true" paginationType="fraction">
<ion-slides pager="true" paginationType="progressbar">
<ion-slides spaceBetween="20">
"<ion-slides speed="250">
"<!-- Slider con función de zoom habilitada -->
<ion-slides zoom="true">
<ion-slide>
<div class="swiper-zoom-container">
<img src="ruta/a/imagen1.jpg" alt="Imagen 1">
</div>
</ion-slide>
<ion-slide>
<div class="swiper-zoom-container">
<img src="ruta/a/imagen2.jpg" alt="Imagen 2">
</div>
</ion-slide>
<ion-slide>
<div class="swiper-zoom-container">
<img src="ruta/a/imagen3.jpg" alt="Imagen 3">
</div>
</ion-slide>
</ion-slides>
Bien, pues estas son las propiedades aisladas de nuestro componente. Ahora vamos a ver una cosita que no hemos visto en el resto de tutos. Seguramente, y después de decisión popular de la comunidad, voy a incluirla en todos los tutos que ya he hecho.
Se trata de la salida, OutputEvents, que emite el componente cuando ya ha realizado alguna opción y que podemos escucharlas para dar servicio adicional a nuestros usuarios.
En el caso de que queramos que el slider tenga una funcionamiento autónomo, independientemente de si el usuario lo usa, o no, tendremos que realizar los siguiente:
Estas serán las opciones de configuración que tenemos que meter
slideOptsOne = {
initialSlide: 0,
slidesPerView: 1,
autoplay:true
};
Ahora veamos el Slider en si:
<ion-slides [options]="slideOptsOne">
<ion-slide *`ngFor`="let item of topStories">
<ion-card (click)=" this.newsService.onGoToTopStoryPage(item)">
<ion-card-content>
<ion-img [src]="item.image"></ion-img>
<h2> <b>{{item.title}} </b></h2>
<h4>{{item.summary}}</h4>
</ion-card-content>
</ion-card>
</ion-slide>
</ion-slides>
¿Ves? Es super sencillito :)
Vale, como he comentado por encima en el párrafo anterior, este componente emite un determinado número de eventos cuando se realiza X acción. Estos eventos, como llegar al final de un slide o haber llegado al final de la cola, se pueden controlar para que hagamos determinadas acciones. Vamos a verlos.
Nota: Para controlarlos tendremos que llamarlos desde el HTML y pasarle entre las comillas la función que queremos ejecutar. También pueden recibir parámetros.
Este evento es llamado cuando el Slider ionic comienza el movimiento.
Ejemplo: "<ion-slides (ionSlideAutoplay)="miFuncionEnTs()">
"
Este evento se ejecuta cuando es llamado el evento autoplayStart que hemos visto en puntos anteriores.
Ejemplo: "<ion-slides (ionSlideAutoplayStart)="miFuncionEnTs()">
"
Similar al anterior, pero es llamado cuando se llama a autoplayStop.
Ejemplo: "<ion-slides (ionSlideAutoplayStop)="miFuncionEnTs()">
"
Este callback es llamado cuando una transacción ha terminado. No importa la posición en la que esté nuestro componente. Será llamado con cada una de ellas.
Ejemplo: "<ion-slides (ionSlideDidChange)="miFuncionEnTs()">
"
Como su propio nombre indica, es llamado cuando el usuario hace doble click sobre cualquiera de las diapositivas.
Ejemplo: "<ion-slides (ionSlideDoubleTap)="miFuncionEnTs()">
"
Es llamado cuando el usuario usa el evento de sistema drag (arrastrar) sobre nuestro módulo.
Ejemplo: "<ion-slides (ionSlideDrag)="miFuncionEnTs()">
"
Es invocado cuando uno de los slides termina el recorrido (hacia adelante) de cualquier slide.
Ejemplo: "<ion-slides (ionSlideNextEnd)="miFuncionEnTs()">
"
El similar al anterior pero cuando comienza en lugar de cuando acaba.
Ejemplo: "<ion-slides (ionSlideNextStart)="miFuncionEnTs()">
"
Es solicitado cuando uno de los slides termina el recorrido (hacia atrás) de cualquier slide.
Ejemplo: "<ion-slides (ionSlidePrevEnd)="miFuncionEnTs()">
"
Similar al anterior, pero al comienzo en lugar de cuando acaba.
Ejemplo: "<ion-slides (ionSlidePrecStart)="miFuncionEnTs()">
"
Se emite cuando el Slider ha llegado a su última diapositiva. Muy útil para controlar, por ejemplo, si queremos cambiar el contenido del Slider.
Ejemplo: "<ion-slides (ionSlideReachEnd)="miFuncionEnTs()">
"
Se emite cuando el slider vuelve a su posición inicial. Es importante saber que no se ejecutará aunque el usuario lleve el Slider al comienzo o en la primera carga del componente.
Ejemplo: "<ion-slides (ionSlideReachStart)="miFuncionEnTs()">
"
El solicitado cuando el usuario hace un tap sobre cualquiera de los componentes de nuestro slide. Es más, recibe parámetros que nos permitirán saber cual es la posición sobre la que se ha hecho el tap.
Ejemplo: "<ion-slides (ionSlideTap)="miFuncionEnTs()">
"
Similar al que hemos visto un poco más arriba. Este evento es llamado cuando comienza un cambio de diapositiva. Sea cual sea.
Ejemplo: "<ion-slides (ionSlideWillChange)="miFuncionEnTs()">
"
Y visto todo esto vamos a pasar a comentar algunas cosillas que me parecen interesantes que las sepas.
Me gustaría comentar este punto, es algo que muchos de mis usuarios me han pedido. Y aunque tu quizás no, por que si no no estarías aquí, lo voy a explicar para los que si que les interese.
Pues bien, seré breve. Las Options de los Slides han desaparecido / deprectated a partir de la versión 2 de Ionic y si quieres hacer un buen uso del componente tendrás que manejar todo mediante TypeScript.
Este movimiento me parece muy aconsejable por parte de la plataforma dado que, en un componente tan complejo, dejar al aire propiedades en el HTML me parecería un retraso más que un avance.
Pues bien, pregunta contestada :)
Mira, en el momento que tu mejoras el logo de una app que tengas publicada en Google Play, las descargas y los ingresos que esta aplicación genera aumentan. Esto es así. Mejor logo es igual a más dinero.
Basándonos en esto, hemos creado esta herramienta que te permite evaluar, optimizar y mejorar los logos de tus apps para que reciban más descargas. No te quiero espoilear, dentro hay un video explicativo. Entra en el enlace.
Y ahora si geniete, ya hemos terminado. Espero haberte ayudado y nos vemos en el siguiente artículo. Hasta entonces ¡que te vaya bien!