Archivo de la etiqueta: directive

Directiva para mostrar y ocultar men煤 al hacer scroll en Ionic

 

隆隆Atenci贸n!! este tutorial se basa en ionic 3 y est谩 desactualizado por lo que es posible que los ejemplos no funcionen en la 煤ltima versi贸n de ionic, haz click aqu铆 para acceder a un tutorial mas actual de Ionic.

En el siguiente enlace tienes el 铆ndice para acceder al resto de entradas de este tutorial:

Hola a todos:

El post de hoy es por cortes铆a de Miguel Escribano.

Miguel ha realizado una app en ionic para consultar las noticias de men茅ame que est谩 realmente bien y que pod茅is encontrar en google play en el siguiente enlace:

https://play.google.com/store/apps/details?id=com.miguelescribano.meneame

Bi茅n, Miguel聽聽que ha querido colaborar aportando una directiva para mostrar u ocultar un men煤 o barra de herramientas al hacer scroll:

Una directiva es un tipo de componente pensado para cambiar el comportamiento de un elemento ya existente en el DOM. 聽A diferencia de un componente normal este no necesita de una plantilla sino que se incrustara en una existente para manipularla.

El objetivo aqu铆 es esconder una barra de navegaci贸n al hacer scroll hacia abajo y que aparezca cuando hacemos scroll hacia arriba.

En ionic el evento de scroll se produce en el content, por tanto dicha barra ha de encontrarse dentro de ion-content.

Vamos a crear un proyecto de prueba para mostrar como funciona esta directiva:

ionic start hideMenu blank

Vamos a editar home.ts聽y le vamos a a帽adir un array con los items que mostraremos en el listado, por ejemplo una lista de videojuegos:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  items = [
    'Pokemon Yellow',
    'Super Metroid',
    'Mega Man X',
    'The Legend of Zelda',
    'Pac-Man',
    'Super Mario World',
    'Street Fighter II',
    'Half Life',
    'Final Fantasy VII',
    'Star Fox',
    'Tetris',
    'Donkey Kong III',
    'GoldenEye 007',
    'Doom',
    'Fallout',
    'GTA',
    'Halo',
    'Warcraft II'
  ];

  constructor(public navCtrl: NavController) {

  }

}

Ahora vamos a editar home.html y a帽adimos el siguiente c贸digo en amarillo en ion-content para generar la toolbar y los items de prueba:

<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content hide-menu>

      <ion-toolbar no-border-top class='show-header'>
          <ion-segment color='secondary' [(ngModel)]="section">
            <ion-segment-button value="portada">
              Portada
            </ion-segment-button>
            <ion-segment-button  value="nuevas" >
              Nuevas
            </ion-segment-button>
            <ion-segment-button  value="populares">
              Populares
            </ion-segment-button>
            <ion-segment-button  value="mas_visitadas">
              + Visitadas
            </ion-segment-button>
          </ion-segment>
        </ion-toolbar>

    <ion-list>
      <button ion-item *ngFor="let item of items" (click)="itemSelected(item)">
        {{ item }}
      </button>
    </ion-list>
</ion-content>

Como pod茅is ver en la etiqueta ion-content hemos a帽adido hide-menu聽 que es el nombre de la directiva que vamos a crear.

Despu茅s hemos a帽adido una聽 ion-toolbar con ion-segment聽 y cuatro opciones que ser谩 la barra de men煤 que vamos a mostrar u ocultar.

Por ultimo mostramos un listado donde mostramos con *ngFor los items que hemos definido en el controlador.

V茅ase que de entrada la barra tiene la clase show-header. Incluiremos esta y hide-header en la listado.scss con la intenci贸n de hacerla aparecer y desaparecer respectivamente.

Tambi茅n necesitamos definir la posici贸n de聽ion-tollbar como fixed.

Suponiendo que nuestro header principal (ion-header) tiene la altura 56px por defecto incluiremos lo siguiente en listado.scss:

page-home {

    ion-toolbar {
        position:fixed;
    }

    .hide-header{
        top: 0px;
    }

    .show-header{
        top: 56px;
    }
   
 }

Ya solo queda crear la directiva, para ello vamos a utilizar ionic generator:

ionic g directive hide-menu

Al generar la directiva nos habr谩 creado una carpeta directives y dentro estar谩 la carpeta hide-menu con la directiva que acabamos de crear.

Necesitamos declarar la directiva en app.module.ts,聽por lo tanto lo editamos y a帽adimos lo siguiente:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { HideMenuDirective } from '../directives/hide-menu/hide-menu';

@NgModule({
  declarations: [
    MyApp,
    HomePage,
    HideMenuDirective
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

Ahora editamos el archivo hide-menu.ts聽de nuestra directivay vamos a importar聽e inyectar en el constructor ElementRef,聽 Renderer2, que necesitaremos para manipular los elementos de la vista:

import { Directive, ElementRef, Renderer2  } from '@angular/core';

/**
聽* Generated class for the HideMenuDirective directive.
聽*
聽* See https://angular.io/api/core/Directive for more info on Angular
聽* Directives.
聽*/
@Directive({
  selector: '[hide-menu]' // Attribute selector
})
export class HideMenuDirective {

  constructor(public element:ElementRef, public renderer:Renderer2) {
    console.log('Hello HideMenuDirective Directive');
  }

}

Vemos que en el decorador @Directive viene definido el selector que es el que tenemos que poner en el elemento de la vista al que queremos aplicar la directiva.

Ahora en la definici贸n de la directiva a la propiedad聽host聽le vamos a asignar el evento ionScroll聽y le indicamos que ejecute la funci贸n handleScroll que definiremos despu茅s. Host hace referencia al elemento donde estamos aplicando la directiva, en este caso se lo estamos asignando al elemento ion-content:

@Directive({
  selector: '[hide-menu]', // Selector de la directiva
  host: {
    '(ionScroll)': 'handleScroll($event)' // Captura el evento scroll (ionScroll) dentro de ion content y env铆a el evento a su manejador handleScroll
  }
})

Ahora necesitamos definir tres variables:

toolBarRef – Hace referencia a la toolbar que vamos a mostrar u ocultar.
storedScroll – Guardar谩 la posici贸n del scroll.
threshold – Contendr谩 la distancia que tenemos que mover el scroll para que se oculte la barra.
export class HideMenuDirective {


  private toolBarRef:any;

  private storedScroll: number = 0;
  private threshold: number = 10;


  constructor(public element:ElementRef,
              public renderer:Renderer2) {
  }

Una vez definidas las variables en ngOnInit 聽hacemos que toolBarRef聽 referencie al elemento del DOM que contiene la barra,聽聽ngOnInit聽se ejecuta una 煤nica vez al iniciar,聽 es parecido al constructor:

ngOnInit() {
    //Con esto conseguimos referenciar la barra de navegacion mediante su clase.
    this.toolBarRef = this.element.nativeElement.getElementsByClassName("toolbar")[0];
  }

Una vez hecho esto ya podemos definir la funci贸n handleScroll聽que como hemos indicado se ejecutar谩 al hacer scroll sobre el elemento ion-content al que hemos asignado la directiva:

handleScroll(event) {
    if (event.scrollTop - this.storedScroll > this.threshold) {
      //al hacer scroll down hace desaparecer la barra mediante clases
      this.renderer.addClass(this.toolBarRef,'hide-header');
      this.renderer.removeClass(this.toolBarRef,'show-header');
    } else if (event.scrollTop - this.storedScroll < 0) {
       //al hacer scroll up la hace aparecer de nuevo
      this.renderer.removeClass(this.toolBarRef,'hide-header');
    }
    //actualizmos la ultima posicion conocida del scroll proveniente del evento
    this.storedScroll = event.scrollTop;
  }

En esta funci贸n comprobamos si la posici贸n actual del scroll (event.scrollTop) menos la posici贸n anterior es mayor que el limite (threshold), si es as铆 es que estamos haciendo scroll hacia abajo por lo tanto con this.renderer.addClass le a帽adimos a la toolbar la clase hide-header que har谩 que se oculte la barra y con removeClass eliminamos la clase show-header que tenia.

En caso contrario significa que estamos haciendo scroll hacia arriba por lo tanto eliminamos la clase hide-header que oculta la barra, lo que har谩 que esta se vuelva a mostrar.

El c贸digo completo de la directiva quedar铆a as铆:

import { Directive, ElementRef, Renderer2 } from '@angular/core';

@Directive({
  selector: '[hide-menu]', //selector de la directiva
  host: {
    '(ionScroll)': 'handleScroll($event)' //Captura el evento scroll (ionScroll) dentro de ion content y envia el evento a su manejador handleScroll
  }
})
export class HideMenuDirective {

  //Varaibles para referenciar la barra 
  private toolBarRef:any;

  //Variables para saber la direccion del scroll
  private storedScroll: number = 0;
  private threshold: number = 10;


  constructor(public element:ElementRef,
              public renderer:Renderer2) {
  }

  ngOnInit() {
    //Con esto conseguimos referenciar la barra de navegacion mediante su clase.
    this.toolBarRef = this.element.nativeElement.getElementsByClassName("toolbar")[0];

  }

  handleScroll(event) {
    if (event.scrollTop - this.storedScroll > this.threshold) {
      //al hacer scroll down hace desaparecer la barra mediante clases
      this.renderer.addClass(this.toolBarRef,'hide-header');
      this.renderer.removeClass(this.toolBarRef,'show-header');
    } else if (event.scrollTop - this.storedScroll < 0) {
       //al hacer scroll up la hace aparecer de nuevo
      this.renderer.removeClass(this.toolBarRef,'hide-header');
    }
    //actualizmos la ultima posicion conocida del scroll proveniente del evento
    this.storedScroll = event.scrollTop;
  }
}

Si ejecut谩is el ejemplo con ionic serve -l obtendreis algo como esto:

Bien, eso es todo por hoy, solo me resta agradecer a Miguel Escribano por su aporte y recomendaros que descargu茅is su app meneame.

 

Si necesitas desarrollar una aplicaci贸n m贸vil no dudes en solicitarme un presupuesto sin compromiso: