Repository: Ionic Github Repository
Software Requirements:
Visual Studio Code(Or any preferred code editor),
npm, ionic.
What you will learn:
In this tutorial you would learn about how to manage your ionic/Electron app on whatever platform you choose to target covering these major concepts
- How to create a header directive
- Implementing the directive in the module
- Implementing your header bar in the template
Tutorial
Ionic is a hybrid web application, which means that ionic is running in the web view. In light of this, no matter how well ionic developers try ,they cant get that exact native feeling no matter how they try. The best way to go is to prevent numerous dom changes depending on the devices your users may be running your app on.
On an iphone or samsung with a marvelous GPU and marvelous RAM of about 8gigg ram, the changes on the dom would not be noticed but on other average phones the lag would affect performance and make it feel less user friendly. In one of my previous tutorial i made a dismissible header bar but in this tutorial the header bar we would be making would be more user friendly and would look more native.
We cannot make the header to absolutely sync with the scroll events so we would just initiate the animation based on the scroll events. In most native apps these animated effects help improve user effect significantly and with ionic we're trying to achieve that.
At the end of this post you can find a starter project with the expandable header and press and hold event already enabled so if you would like use the starter project you're free just clone the GITHUB repo at the end of this repo.
Lets get started...
Before we progress i would like you to see a short gif of what we would be trying to achieve
In the last header tutorial done last year we used a component, in this tutorial i would be using a directive which is much better and easier to implement in the app. Directives are the names implied additional scripts you can add to already made components to make them work more suitably for your needs.
So rather than making a whole component that rises and shrinks we can simply add a directive to a normal ion-toolbar
to make it rise and shrink as we please.
Creating a header directive and implementing it
A directive can be created using the ionic angular command
First make a directory
mkdir directives
navigate into it
cd directives
and create the directives
ionic g directive expandableHeader
So lets get to the logic
import { Directive, Input, ElementRef, Renderer2, OnInit } from '@angular/core';
import { Observable, fromEvent } from 'rxjs';
import { DomController } from '@ionic/angular';//Important for managing DOM events
@Directive({
selector: '[myScrollVanish]'
})
export class ExpandableHeaderDirective implements OnInit {
@Input('myScrollVanish') scrollArea;
// To detect what position the header is in so that you don't trigger too many events into the dom
private hidden: boolean = false;
private triggerDistance: number = 20;
constructor(private element: ElementRef, private renderer: Renderer2, private domCtrl: DomController) {
}
ngOnInit(){
console.log(this.scrollArea)
// Wait until 'ion-scroll' element is added to 'ion-content'
this.initStyles();
this.scrollArea.ionScroll.subscribe((scrollEvent: CustomEvent) => {
let delta = scrollEvent.detail.deltaY;
if(scrollEvent.detail.currentY === 0 && this.hidden){
this.show();
}
else if(!this.hidden && delta > this.triggerDistance){
this.hide();
} else if(this.hidden && delta < -this.triggerDistance) {
this.show();
}
});
}
initStyles(){
this.domCtrl.write(() => {
this.renderer.setStyle(this.element.nativeElement, 'transition', '0.3s linear');
});
}
hide(){
this.domCtrl.write(() => {
this.renderer.setStyle(this.element.nativeElement, 'min-height', '0px');
this.renderer.setStyle(this.element.nativeElement, 'height', '0px');
this.renderer.setStyle(this.element.nativeElement, 'opacity', '0');
this.renderer.setStyle(this.element.nativeElement, 'padding', '0');
});
this.hidden = true;
}
show(){
this.domCtrl.write(() => {
this.renderer.setStyle(this.element.nativeElement, 'height', '55px');
this.renderer.removeStyle(this.element.nativeElement, 'opacity');
this.renderer.removeStyle(this.element.nativeElement, 'min-height');
this.renderer.removeStyle(this.element.nativeElement, 'padding');
});
this.hidden = false;
}
}
The next thing would be to implement and use this directive.
For ionic 4 apps, managing modules is very important and since lazy loading is not more optional we have to deal with modules optimally.
Note: I would be importing the module into the page is is being used in, this would minify your code and help with boot time.
Implementing the directive in the pages module
As stated above we would be implementing the directive only in the page that we would be using it. So head to your homepage.ts and implement it as such
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { HomePage } from './home.page';
import { ExpandableHeaderDirective } from '../expandable-header.directive';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild([
{
path: '',
component: HomePage
}
])
],
declarations: [HomePage,ExpandableHeaderDirective]
})
export class HomePageModule {}
and then we can move to implementation
Implementing the directive in your template
To implement this in the template you simply use the directly part of the template in whichever component you would like to use it in
<ion-header>
<ion-toolbar color="primary" [myScrollVanish]="scrollArea">
<ion-buttons slot='end'>
<ion-button (click)="delete()">
<ion-icon name='trash'>
<ion-badge>{{ this.selected.length }}</ion-badge>
</ion-icon>
</ion-button>
</ion-buttons>
<ion-title text-center>Press and Hold Starter</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding #scrollArea scrollEvents="true">
<ion-list>
<ion-item *ngFor="let item of myArray; let i = index" (press)="onHold($event,item)" (click)="onClick($event,item)">
<h2>{{ item }}</h2>
</ion-item>
<div class="nothing" *ngIf="myArray.length < 1">
<h2>
Nothing Here
</h2>
</div>
</ion-list>
</ion-content>
Hopefully everything should work from this point and you can leave a comment if you have any issues implementing this yourself. You can however download this with my hold and select feature from the last tutorial as a starter template
GITHUB REPO
Thanks for reading