Aitor Sánchez - Blog - Oct. 30, 2023, 6:37 p.m.
Así que quieres incluir un menú de acciones flotante con el plugin Action Sheet Ionic ¿verdad? O, talvez, ya sabes cómo se hace pero te falta alguna función o campo para ponerlo a tu gusto ¿cierto?
Mi nombre es Aitor Sánchez, soy desarrollador de apps desde 2014, Y en este artículo vas a aprender a implementar este tipo de menús y cómo hacer funcionar un Action Sheet de Ionic. Ese menú tan de moda, e interesante, que aparece flotando desde la parte inferior de la pantalla.
Pero antes de continuar, esta es la Flutter Mafia. Es mi newsletter donde tu vas a aprender a hacer apps y a ganar dinero con ellas 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.
Y ahora si, comenzamos ¡Let´s go!
Bueno, comenzamos hablando de este controlador porque es el encargado de darnos acceso a todo el componente Action Sheet desde nuestro código TypeStript. Al tratarse de un componente púramente visual, y estar incluido en el core, no será necesaria la instalación de ningún plugin.
En primer lugar, para poder utilizarlo, como es constumbre, tenemos que importarlo en nuestras dependencias como hacemos con todos los controladores. Para ello nos vamos a dirigir a nuestro "app.modules.ts" y dentro de la construcción de nuestro @NgModule insertamos lo que vamos a ver a continuación
@NgModule({
declarations: [
...
],
imports: [
...
],
bootstrap: [IonicApp],
entryComponents: [
...
],
providers: [
...
ActionSheetController, //Esta es la línea importante.
...
]
})
¿Sencillo verdad? Si eres nuevo, esto te parecerá un poco raro. Pero para que los que ya tenemos un poco de camino recorrido nos resultará familiar.
Con este código ya estamos en disposición de injectar nuestro controlador ActionSheet en cualquier componente de nuestra app, sigamos.
En la actualidad, a fecha de actualización del artículo, día 28/10/2019, el sistema es soportado por las siguientes plataformas:
Los ejemplos que vas a ver aquí te van a valer para cualquiera de las plataforemas que hemos visto en la lista.
Bien, vamos a proceder a hacer una construcción simple de este component y explico un poco de que va el tema después sobre esta demo.
Nota: Este ejemplo/example es totalmente funcional. Si lo quieres utilizar, estás en todo tu derecho :) Es más, te serviría para Ionic 2, Ionic 3 y Ionic 4 a fecha de publicación del artículo.
import { ActionSheetController } from 'ionic-angular'
export class MiClase{
constructor(public miAc: ActionSheetController) {} //Injectamos el controlador en el consstructor
presentActionSheet() {
let actionSheet = this.actionSheetCtrl.create({ //Llamamos a la función create para contruir nuestro componente.
title: 'Modify your album', //El título de nuestro ActionSheet
//Este array define los botones que van a ir dentro de nuestro contenedor
buttons: [
{
text: 'Destructive',
role: 'destructive',
handler: () => {
console.log('Destructive clicked');
}
},
{
text: 'Archive',
handler: () => {
console.log('Archive clicked');
}
},
{
text: 'Cancel',
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}
]
});
actionSheet.present(); //Esta es la función que llama al ActionSheet para que sea mostrado.
}
}
Una cosa más antes de continuar, actualmente los Ionic Action Sheet no son scrollables. Por lo que no deberías agregar muchos botones de acción y siempre probar si todo va cómo quieres que se vea en varias pantallas antes de lanzar nada a producción. De otra manera, podrías encontrar sorpresas ingratas.
Aquí tienes todas las opciones / options y parámentros / parámeters de construcción que se le pueden pasar en el método create:
var options = {
androidTheme: window.plugins.actionsheet.ANDROID_THEMES.THEME_DEVICE_DEFAULT_LIGHT, // Este es el tema por defecto, revisar las coonstantes y poréis ver más.
title: 'Este es el title de nuetro action sheet',
subtitle: 'Este es el subtitulo o la descripción', // Solo soportado en iOS
buttonLabels: ['Compartir en Facebook', 'Compartir en Twitter'],
androidEnableCancelButton : true, // por defecto false
winphoneEnableCancelButton : true, // por defecto false
addCancelButtonWithLabel: 'Cancelar',
addDestructiveButtonWithLabel : 'Eliminar esto',
position: [20, 40], //Solo es para los iPad y hay que pasarle la position X y el position Y de donde queremos que se muestre.
destructiveButtonLast: true // Por si quieres mostrar un botón de destrucción :)
};
Si por algo defiendo Ionic es por la simpleza que tiene en la elaboración, escirtura y lectura de nuestro código. Cosas así programadas en Java nativo doblan, practicamente, la cantidad de código necesaria para contruirlas.
Como hemos podido ver, solo tenemos que inyectar el controlador del ActioSheet en nuestro contructor y listo, ya lo podemos usar.
La función contruct, nos permite pasarle todos los parametros a nuestro componente para que se contruya "solo". Los componentes que contiene un ActionSheet dentro de su contenedor son todos botones, con sus respectivas reglas y demas...
A parte tiene la posibilidad de incluir en él un "title", "subtitle" y un "icono" para que queda aún más bonito.
En primer lugar comentar, como hemos visto en el código, que todos los componentes internos del contenedor son buttons. Esta es una regla importante de conocer.
Todos los botones tienen la propiedad "role" aunque nosotros no se la pongamos. De forma predeterminada tomarán el aspecto de la plataforma pero podemos asignarles 2 tipos más:
Por último comentar que las opciones del componente las podemos inicializar todas en la función "Create()" o asignarlas con sus funciones "set" como por ejemplo: "setTitle()". Y para agregar más botones: "addButton()".
Veamos un ejemplo de la matriz de botones:
buttons: [
{
text: 'Destruir AccionSheet',
role: 'destructive',
handler: () => {
console.log('Destruir clicked');
}
},
{
text: 'Información sobre la aplicación',
handler: () => {
console.log('Información clicked');
}
},
{
text: 'Cancelar accioones',
role: 'cancel',
handler: () => {
console.log('Cancelar clicked');
}
}
]
De manera dicional recuerda, a parte de que incurres en buenas prácticas, la traducción / translation de la app siempre tiene que estar presente en todo lo que hagas. Lo digo por las cadenas que hemos visto aquí, siempre tráelas desde una traducción.
No existe diferencia en el diseño alguna entre plataformas de manera programática, a excepción de la capa visual y el material design. No tienen diferencia de uso sobre el código. La Action sheet interface select en Ionic es similar, mira:
Muchos de los compañeros con los que trabajo, y hablo, me preguntan cosillas de este tipo. Así que vamos a contestarlas en un segundo:
Mirar: Cada uno de los botones que agregamos a nuestra array de botones tiene las siguientes características:
"text" -> (String) -> Es el texto del botón.
"icon" -> (icon) -> Es el icono que va alineado a la izquierda de la caja que contiene el botón. Hablaremos sobre los iconos más adelante, por que si no tendríamos que hacer otro artículo. Aún así os dejo una referencia donde podéis ver un poco mejor como se usan: https://ionicframework.com/docs/api/components/icon/Icon/
"handler" -> (any) -> La función que se ejecutará cuando el botón sea pulsado.
"cssClass" -> (string) -> Si queremos asignar alguna clase adicional al botón para cambiar el aspecto de este. Con esta clase también podrás cambiar el Ionic Action Sheet icon color y los styles de los buttons. A parte, que no se me olvide, tambíen podrás cambiar el Text Color desde aquí.
"role" -> (string) -> Esta es la zona que hemos comentado antes que tiene dos posibilidades, "cancel y desctructive". Si queres conocer como funciona mira un poco más arriba.
Esta parte es muy sencilla de trabajar. Puedes cerrarlo pulsando en el botón al que le hayas asignado el "role" "cancel". También puedes pulsar fuera de la ventana para cerrarlos sí la propiedad "enableBackdropDismiss" esta seteada a "false" (de forma predeterminada es false) o cerrarlo programáticamente cuando queramos. Pero también se puede dar el caso de que queramos cerrarlos desde código. Entonces tendríamos que llamar al método dismiss de la instancia action sheet para que se cerrase el modal en Ionic.
Normalmente, los botones de esta opción no suelen ser muchos, pero si tu app lo necesita se puede conseguir que haga Scroll. Cuando la ventan sobrepase un poco más de la mitad de la pantalla (2/3 más o menos) no aumentará más y se pondrá en modo Scrool automáticamente. Es así, tan sencillo que asusta.
Llegará un punto, que si estás aquí será por que seguramente no has llegado, yo estoy llegando ahora, en el que "todo es posible de hacer". Te explico, de una manera sencilla no se puede personalizar del todo. Quizás si que podrás tocar las CSS del componente pero poco más.
Para ello existe algo que se llama la herencia, que seguramente hayas oido hablar de ello, o sepás perfectamente lo que es. Pero para este caso no lo voy a explicar así que ilustro un poco por encima y ya veremos más adelante en el curso como lo podemos hacer "bien".
Para solucuionar este problema tendrías que extender el AcctionSheetController con una clase propia y a partir de ahí modificar lo que veas necesario. Podríamos poner, por ejemplo, una barra de búsqueda, personalizar los eventos click, long-click, pane, etc... a placer o cambiar directivas del componente desde la misma raiz. Pero como digo, esto daría para un curso completo, así que lo veremos más adelante.
Muchos compañeros/conocidos han tenido problemas con este tipo de componentes, pero nada que no se solucione echando un ojo detallado al código y comprobando si la lógica de negocio está correcta. Estamos en una versión bastante avanzada y madura de Ionic. No tiene mucho sentido que algo así pase.
Pero para cuando sucede cada caso es un mundo. Si has tenido alguno de estos problemas mándame un mail y estaré encanto de ayudarte.
Es posible, sobre todo en algunas versiones de Android, que cuando pulsamos el botón de regresar no se esconda la ventana de un Action Sheet. Para solucionarlo, basta con que controlemos el tap del back button con nuestro código y que escondamos nosotros de manera explicita el modal.
this.platform.registerBackButtonAction(() => {
let nav = this.app.getActiveNav();
if (nav.canGoBack()){ //Can we go back?
nav.pop();
}else{
let actionSheet = this.actionSheetCtrl.create({
title: 'Realmente desea salir?',
buttons: [
{
text: 'Si, salir',
handler: () => {
this.platform.exitApp(); //Exit from app
}
},{
text: 'Cancelar',
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
}
}
]
});
actionSheet.present();
}
});
¿Ves que sencillo es? Pruébalo, es totálmente funcional :)
Ya son varias las preguntas que estoy procurando ir constestando a los usuarios del blog. Pues bien, para poder enviar data desde un Action Sheet de manera dinámica lo que tenemos que hacer es construir el Action Sheer en si con esta configuración de botones:
let actionSheet = ActionSheet.create();
...
for (var i = 0; i < array.length; i++){
actionSheet.addButton({
text: title,
handler: this.miFuncion.bind(this, i)
})
}
...
miFuncion(i){
//Entonces aquí, por ejemplo, extraemos el índice del botón que se ha pulsado
//array[i] tendría los datos que necesitamos recuperar. Si alguna vez has programado en Android, esto lo entenderás a la primera por que es similar a las listas.
}
Bien, aunque esto es refernte a Angular 1, hay gente que aún me lo pregunta por que tiene proyectos en esta versión del Framework y vamos a proceder a contestar esta questión. La verdad que no es algo que sea complicado, pero si que tiene un poco de miga por que el sitema no está enfocado para ello. Veamos...
angular.module('ionicApp', ['ionic'])
.service('$options', function ($ionicActionSheet) {
return {
show: function () {
console.log('Inténtalo');
var buttons = [
{text: 'Botón 1'},
{text: 'Botón 2'},
{text: 'Botón 3'}
];
$ionicActionSheet.show({
titleText: 'ActionSheet de ejemplo',
buttons: buttons,
destructiveText: 'Eliminar',
cancelText: 'Cancelar',
cancel: function() {
console.log('CANCELADO');
},
buttonClicked: function(index) {
alert('BOTÓN CLICADO '+ index);
return true;
},
destructiveButtonClicked: function() {
console.log('DESTRUIDO');
return true;
}
});
}
}
})
.directive('fOptions', function($options) {
return {
restrict: 'E',
template: '<button class="button button-icon right-buttons icon ion-ios7-more"></button>',
link: function (scope, element) {
element.on('click', function () {
scope.$apply(function(){
$options.show();
});
console.log('Clicckkk');
});
element.on('$destroy', function () {
element.off('click');
console.log('Yeeee');
});
}
};
});
Al final con el código que vemos estamos creando un servicio y una directiva a parte del $scope y lo lanzamos desde este una vez ya está inicializada la aplicación. Hay que leer en profundidad el código para entenderlo. Y a parte, la contrucción del grupo / group de botones también influye en la construcción del Action Sheet.
Llevo media hora investigando, mientras escribo la respuesta, de si es posible incluir un input dentro de este componente. Yo, directamente sabía que no se podía, o no era probable, y el resto de comunidad me loa ha confirmado. No se puede de manera natural incluir un input en este componente.
Ahora bien, en desarrollo se puede hacer lo que nos de la gana, con lo que nos de la gana, si sabesmo cómo hacerlo. Siempre podemos extender la funcionalidad del componente en cuestión y hacer uno custom. Es más, seguro que ya hay gente lo que ha hecho. Más adelante en el curso, yo mismo os enseñaré cómo se hace, pero hasta ahora no puedo ayudar más con esta pregunta. Lo siento :(
Debido a que el artículo ya se está haciendo un poco largo de más, he decidido que sea un compañero de batalla quien os explique cómo se pueden deshabilitar los botones de un Action Sheet. La verdad que es un poco rudimentario el ejemplo, pero funcional. Aún no hay una capa de abstracción sobre esto, así que toca picar código. Todo vuestro.
Mira, el logo de tu aplicación es una de las parte más importantes a nivel de ASO. Símplemente mejorándolo un poco se nota activamente en tus descargas y tus ingresos. Pues bien, basándonos en esto, hemos construido una herramienta que te va a ayudar a evaluar, mejorar y optimizar los logos de tus aplicaciones y a espiar los de la competencia. Aquí tienes todos los detalles.
Y hasta aquí el artículo de hoy geniete, espero haberte ayudado. Nos vemos en el siguiente. Hasta entonces, ¡que vaya bien!